% \iffalse meta-comment
% !TeX program  = XeLaTeX
% !TeX encoding = UTF-8
%
% $Id: ctex.dtx 772 2015-03-12 05:33:18Z leoliu.pku@gmail.com $
% $URL: http://ctex-kit.googlecode.com/svn/branches/ctex/ctex.dtx $
%
% Copyright (C) 2003--2015
% CTEX.ORG and any individual authors listed elsewhere in this file.
% --------------------------------------------------------------------------
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
% version 1.3c of this license or (at your option) any later
% version. This version of this license is in
%    http://www.latex-project.org/lppl/lppl-1-3c.txt
% and the latest version of this license is in
%    http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of
% LaTeX version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainers of this work are Leo Liu, Qing Lee and Liam Huang.
% --------------------------------------------------------------------------
%
%<*internal>
\iffalse
%</internal>
%<*readme>
ctex is a collection of macro packages and document classes
for LaTeX Chinese typesetting.

This package is licensed in LPPL.

The authors and contributors of this package are:

    * Wu Lingyun <aloft@ctex.org>
    * Jiang Jiang <gzjjgod@gmail.com>
    * Wang Yue <yuleopen@gmail.com>
    * Liu Haiyang <leoliu.pku@gmail.com>
    * Li Yanrui <liyanrui.m2@gmail.com>
    * Chen Zhichu <zhichu.chen@gmail.com>
    * Li Qing <sobenlee@gmail.com>
    * Liam Huang <liamhuang0205@gmail.com>

If you are interested in the process of development you
may observe

    http://code.google.com/p/ctex-kit/updates/list

Report feedback in the Issues section of ctex-kit project,
or in [ctex](http://bbs.ctex.org) forum.

This package consists of the file ctex.dtx, and the derived files

    ctex.pdf,
    ctex.ins,
    ctex.sty,
    ctexcap.sty,
    ctexsize.sty,
    ctexart.cls,
    ctexbook.cls,
    ctexrep.cls,
    ctex-article.def,
    ctex-book.def,
    ctex-report.def,
    ctexcap-gbk.cfg,
    ctexcap-utf8.cfg,
    ctex.cfg,
    ctexopts.cfg,
    ctex-engine-pdftex.def,
    ctex-engine-xetex.def,
    ctex-engine-luatex.def,
    c19rm.fd,
    c19sf.fd,
    c19tt.fd,
    c70rm.fd,
    c70sf.fd,
    c70tt.fd,
    ctex-fontset-windows.def,
    ctex-fontset-adobe.def,
    ctex-fontset-fandol.def,
    ctex-fontset-mac.def,
    ctex-fontset-founder.def,
    ctex-fontset-ubuntu.def,
    ctexspa.def,
    ctexpunct.spa,
    ctexmakespa.tex,
    ctexspamacro.tex,
    zhwinfonts.tex,
    zhadobefonts.tex,
    zhfandolfonts.tex,
    zhfounderfonts.tex,
    zhubuntufonts.tex, and
    README (this file).

%</readme>
%<*internal>
\fi
\begingroup
  \def\temp{LaTeX2e}
\expandafter\endgroup\ifx\temp\fmtname\else
\csname fi\endcsname
%</internal>
%<*install>

\input l3docstrip.tex

\keepsilent
\askforoverwritefalse

\preamble

    Copyright (C) 2003-2015
    CTEX.ORG and any individual authors listed in the documentation.
------------------------------------------------------------------------------

    This work may be distributed and/or modified under the
    conditions of the LaTeX Project Public License, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status `maintained'.

    The Current Maintainers of this work are Leo Liu, Qing Lee and Liam Huang.
------------------------------------------------------------------------------

\endpreamble

\postamble

    This package consists of the file  ctex.dtx,
                 and the derived files ctex.pdf,
                                       ctex.ins,
                                       ctex.sty,
                                       ctexcap.sty,
                                       ctexsize.sty,
                                       ctexart.cls,
                                       ctexbook.cls,
                                       ctexrep.cls,
                                       ctex-article.def,
                                       ctex-book.def,
                                       ctex-report.def,
                                       ctexcap-gbk.cfg,
                                       ctexcap-utf8.cfg,
                                       ctex.cfg,
                                       ctexopts.cfg,
                                       ctex-engine-pdftex.def,
                                       ctex-engine-xetex.def,
                                       ctex-engine-luatex.def,
                                       c19rm.fd,
                                       c19sf.fd,
                                       c19tt.fd,
                                       c70rm.fd,
                                       c70sf.fd,
                                       c70tt.fd,
                                       ctex-fontset-windows.def,
                                       ctex-fontset-adobe.def,
                                       ctex-fontset-fandol.def,
                                       ctex-fontset-mac.def,
                                       ctex-fontset-founder.def,
                                       ctex-fontset-ubuntu.def,
                                       ctexspa.def,
                                       ctexpunct.spa,
                                       ctexmakespa.tex,
                                       ctexspamacro.tex,
                                       zhwinfonts.tex,
                                       zhadobefonts.tex,
                                       zhfandolfonts.tex,
                                       zhfounderfonts.tex,
                                       zhubuntufonts.tex, and
                                       README.
\endpostamble

\declarepostamble\emptypostamble
\endpostamble


\generate
  {
    \usedir{tex/latex/ctex}
    \file{ctex.sty}                 {\from{\jobname.dtx}{package,style}}
    \file{ctexcap.sty}              {\from{\jobname.dtx}{package,ctexcap}}
    \file{ctexsize.sty}             {\from{\jobname.dtx}{package,ctexsize}}
    \file{ctexart.cls}              {\from{\jobname.dtx}{class,article}}
    \file{ctexbook.cls}             {\from{\jobname.dtx}{class,book}}
    \file{ctexrep.cls}              {\from{\jobname.dtx}{class,report}}
    \usepostamble\emptypostamble
    \file{ctex-article.def}         {\from{\jobname.dtx}{heading,article}}
    \file{ctex-book.def}            {\from{\jobname.dtx}{heading,book}}
    \file{ctex-report.def}          {\from{\jobname.dtx}{heading,report}}
    \file{ctexcap-gbk.cfg}          {\from{\jobname.dtx}{GBK}}
    \file{ctexcap-utf8.cfg}         {\from{\jobname.dtx}{UTF8}}
    \file{ctex.cfg}                 {\from{\jobname.dtx}{config}}
    \file{ctexopts.cfg}             {\from{\jobname.dtx}{ctexopts}}
    \file{ctex-engine-pdftex.def}   {\from{\jobname.dtx}{pdftex}}
    \file{ctex-engine-xetex.def}    {\from{\jobname.dtx}{xetex}}
    \file{ctex-engine-luatex.def}   {\from{\jobname.dtx}{luatex}}
    \file{c19rm.fd}                 {\from{\jobname.dtx}{rm,c19}}
    \file{c19sf.fd}                 {\from{\jobname.dtx}{sf,c19}}
    \file{c19tt.fd}                 {\from{\jobname.dtx}{tt,c19}}
    \file{c70rm.fd}                 {\from{\jobname.dtx}{rm,c70}}
    \file{c70sf.fd}                 {\from{\jobname.dtx}{sf,c70}}
    \file{c70tt.fd}                 {\from{\jobname.dtx}{tt,c70}}
    \file{ctex-fontset-windows.def} {\from{\jobname.dtx}{fontset,windows}}
    \file{ctex-fontset-adobe.def}   {\from{\jobname.dtx}{fontset,adobe}}
    \file{ctex-fontset-fandol.def}  {\from{\jobname.dtx}{fontset,fandol}}
    \file{ctex-fontset-mac.def}     {\from{\jobname.dtx}{fontset,mac}}
    \file{ctex-fontset-founder.def} {\from{\jobname.dtx}{fontset,founder}}
    \file{ctex-fontset-ubuntu.def}  {\from{\jobname.dtx}{fontset,ubuntu}}
    \file{ctexspa.def}
      {
        \from{\jobname.dtx}  {ctexspa}
        \from{ctexpunct.spa} {}
      }
    \file{ctexmakespa.tex}          {\from{\jobname.dtx}{spa,make}}
    \file{ctexspamacro.tex}         {\from{\jobname.dtx}{spa,macro}}
    \file{zhwinfonts.tex}           {\from{\jobname.dtx}{zhmap,windows}}
    \file{zhadobefonts.tex}         {\from{\jobname.dtx}{zhmap,adobe}}
    \file{zhfandolfonts.tex}        {\from{\jobname.dtx}{zhmap,fandol}}
    \file{zhfounderfonts.tex}       {\from{\jobname.dtx}{zhmap,founder}}
    \file{zhubuntufonts.tex}        {\from{\jobname.dtx}{zhmap,ubuntu}}
    \usedir{source/latex/ctex}
    \file{\jobname.ins}             {\from{\jobname.dtx}{install}}
    \nopreamble\nopostamble
    \usedir{doc/latex/ctex}
    \file{README.txt}               {\from{\jobname.dtx}{readme}}
  }

\catcode32=12\space

\Msg{*************************************************************}
\Msg{*                                                           *}
\Msg{* To finish the installation you have to move the following *}
\Msg{* file into proper directories searched by TeX:             *}
\Msg{*                                                           *}
\Msg{* The recommended directory is TDS:tex/latex/ctex           *}
\Msg{*                                                           *}
\Msg{*     ctex.sty                                              *}
\Msg{*     ctexcap.sty                                           *}
\Msg{*     ctexsize.sty                                          *}
\Msg{*     ctexart.cls                                           *}
\Msg{*     ctexbook.cls                                          *}
\Msg{*     ctexrep.cls                                           *}
\Msg{*     ctex-article.def                                      *}
\Msg{*     ctex-book.def                                         *}
\Msg{*     ctex-report.def                                       *}
\Msg{*     ctexcap-gbk.cfg                                       *}
\Msg{*     ctexcap-utf8.cfg                                      *}
\Msg{*     ctex.cfg                                              *}
\Msg{*     ctexopts.cfg                                          *}
\Msg{*     ctex-engine-pdftex.def                                *}
\Msg{*     ctex-engine-xetex.def                                 *}
\Msg{*     ctex-engine-luatex.def                                *}
\Msg{*     c19rm.fd                                              *}
\Msg{*     c19sf.fd                                              *}
\Msg{*     c19tt.fd                                              *}
\Msg{*     c70rm.fd                                              *}
\Msg{*     c70sf.fd                                              *}
\Msg{*     c70tt.fd                                              *}
\Msg{*     ctex-fontset-windows.def                              *}
\Msg{*     ctex-fontset-adobe.def                                *}
\Msg{*     ctex-fontset-fandol.def                               *}
\Msg{*     ctex-fontset-mac.def                                  *}
\Msg{*     ctex-fontset-founder.def                              *}
\Msg{*     ctex-fontset-ubuntu.def                               *}
\Msg{*     ctexspa.def                                           *}
\Msg{*     ctexmakespa.tex                                       *}
\Msg{*     ctexspamacro.tex                                      *}
\Msg{*     zhwinfonts.tex                                        *}
\Msg{*     zhadobefonts.tex                                      *}
\Msg{*     zhfandolfonts.tex                                     *}
\Msg{*     zhfounderfonts.tex                                    *}
\Msg{*     zhubuntufonts.tex                                     *}
\Msg{*                                                           *}
\Msg{* To produce the documentation run the file ctex.dtx        *}
\Msg{* through XeLaTeX.                                          *}
\Msg{*                                                           *}
\Msg{* Happy TeXing!                                             *}
\Msg{*                                                           *}
\Msg{*************************************************************}

\endbatchfile
%</install>
%<*internal>
\fi
%</internal>
%<*!(readme|install|zhmap|spa)>
%<*!(c19|c70|ctexspa)>
%<*driver|package|class>
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
%</driver|package|class>
\GetIdInfo$Id: ctex.dtx 772 2015-03-12 05:33:18Z leoliu.pku@gmail.com $
%<*driver>
  {ctex source file}
\ProvidesExplFile{\ExplFileName.\ExplFileExtension}
%</driver>
%<style>  {Chinese adapter in LaTeX (CTEX)}
%<style>\ProvidesExplPackage{\ExplFileName}
%<ctexcap>  {Chinese adapter in LaTeX (CTEX)}
%<ctexcap>\ProvidesExplPackage{ctexcap}
%<ctexsize>  {Chinese font size definition (CTEX)}
%<ctexsize>\ProvidesExplPackage{ctexsize}
%<article&!heading>  {Chinese adapter for class article (CTEX)}
%<article&!heading>\ProvidesExplClass{ctexart}
%<book&!heading>  {Chinese adapter for class book (CTEX)}
%<book&!heading>\ProvidesExplClass{ctexbook}
%<report&!heading>  {Chinese adapter for class report (CTEX)}
%<report&!heading>\ProvidesExplClass{ctexrep}
%<article&heading>  {Heading modification for article (CTEX)}
%<article&heading>\ProvidesExplFile{ctex-article.def}
%<book&heading>  {Heading modification for book (CTEX)}
%<book&heading>\ProvidesExplFile{ctex-book.def}
%<report&heading>  {Heading modification for report (CTEX)}
%<report&heading>\ProvidesExplFile{ctex-report.def}
%<GBK>  {Caption with encoding GBK (CTEX)}
%<GBK>\ProvidesExplFile{ctexcap-gbk.cfg}
%<UTF8>  {Caption with encoding UTF8 (CTEX)}
%<UTF8>\ProvidesExplFile{ctexcap-utf8.cfg}
%<config>  {Configuration file (CTEX)}
%<config>\ProvidesExplFile{\ExplFileName.cfg}
%<ctexopts>  {Option configuration file (CTEX)}
%<ctexopts>\ProvidesExplFile{ctexopts.cfg}
%<pdftex>  {(pdf)LaTeX adapter (CTEX)}
%<pdftex>\ProvidesExplFile{ctex-engine-pdftex.def}
%<xetex>  {XeLaTeX adapter (CTEX)}
%<xetex>\ProvidesExplFile{ctex-engine-xetex.def}
%<luatex>  {LuaLaTeX adapter (CTEX)}
%<luatex>\ProvidesExplFile{ctex-engine-luatex.def}
%<windows>  {Windows fonts definition (CTEX)}
%<windows>\ProvidesExplFile{ctex-fontset-windows.def}
%<adobe>  {Adobe fonts definition (CTEX)}
%<adobe>\ProvidesExplFile{ctex-fontset-adobe.def}
%<fandol>  {Fandol fonts definition (CTEX)}
%<fandol>\ProvidesExplFile{ctex-fontset-fandol.def}
%<mac>  {Mac OS X fonts definition (CTEX)}
%<mac>\ProvidesExplFile{ctex-fontset-mac.def}
%<founder>  {Founder fonts definition (CTEX)}
%<founder>\ProvidesExplFile{ctex-fontset-founder.def}
%<ubuntu>  {Ubuntu fonts definition (CTEX)}
%<ubuntu>\ProvidesExplFile{ctex-fontset-ubuntu.def}
  {\ExplFileDate}{2.0}{\ExplFileDescription}
%</!(c19|c70|ctexspa)>
%<rm&c19>\ProvidesFile{c19rm.fd}%
%<sf&c19>\ProvidesFile{c19sf.fd}%
%<tt&c19>\ProvidesFile{c19tt.fd}%
%<rm&c70>\ProvidesFile{c70rm.fd}%
%<sf&c70>\ProvidesFile{c70sf.fd}%
%<tt&c70>\ProvidesFile{c70tt.fd}%
%<ctexspa>\ProvidesFile{ctexspa.def}%
%<c19|c70>  [2014/03/08 v2.0 Chinese font definition (CTEX)]
%<ctexspa>  [2014/06/12 v2.0 Space info for CJKpunct (CTEX)]
%</!(readme|install|zhmap|spa)>
%<*driver>
\ExplSyntaxOff
\let\ctexrevnum\ExplFileVersion
\expandafter\let\csname ver@thumbpdf.sty\endcsname\fmtversion
\documentclass[a4paper,full,numbered]{l3doc}
\usepackage[UTF8, punct = kaiming, heading,
  linespread = 1.2, sub3section]{ctex}
\ctexset{
  abstractname = 简介,
  indexname    = 代码索引,
}
\appto\abstract{\parindent=2\ccwd} ^^A l3doc.cls 设置列表环境中 \listparindent=\z@
\usepackage[toc]{multitoc}
\usepackage{geometry}
\usepackage{tabularx}
\usepackage{unicode-math}
\geometry{includemp,hmargin={0mm,15mm},vmargin={25mm,15mm},footskip=7mm}
\hypersetup{pdfstartview=FitH,bookmarksdepth=subsubsection}
\setcounter{secnumdepth}{4}
\setcounter{tocdepth}{2}
\newcommand*\email{\nolinkurl}
\setmainfont{TeX Gyre Pagella}
\setsansfont{CMU Sans Serif}
\setmonofont[
  UprightFont=* Light, BoldFont=* Bold,
  SlantedFont=* Light Oblique]{CMU Typewriter Text}
\setmathfont{texgyrepagella-math.otf}
\usepackage{xcolor}
\usepackage{caption}
\captionsetup{strut=off}
\makeatletter
%% <--- http://tex.stackexchange.com/a/40896
\patchcmd{\@addtocurcol}%
    {\vskip \intextsep}%
    {\edef\save@first@penalty{\the\lastpenalty}\unpenalty
     \ifnum \lastpenalty = \@M  % hopefully the OR penalty
        \unpenalty
     \else
        \penalty \save@first@penalty \relax % put it back
     \fi
      \ifnum\outputpenalty <-\@Mii
                         \addvspace\intextsep
                         \vskip\parskip
      \else
                         \addvspace\intextsep
      \fi}%
    {\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\@addtocurcol}%
    {\vskip\intextsep \ifnum\outputpenalty <-\@Mii \vskip -\parskip\fi}%
    {\ifnum\outputpenalty <-\@Mii
       \aftergroup\vskip\aftergroup\intextsep
       \aftergroup\nointerlineskip
     \else
       \vskip\intextsep
     \fi}%
    {\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
\patchcmd{\@getpen}{\@M}{\@Mi}
  {\typeout{*** SUCCESS ***}}{\typeout{*** FAIL ***}}
%% --->
\ifxetex
  \let\ctexdocverbaddon\xeCJKVerbAddon
\else
  \let\ctexdocverbaddon\relax
\fi
\setlist{noitemsep,topsep=\smallskipamount}
\newlist{optdesc}{description}{3}
\setlist[optdesc]{%
  font=\mdseries\ttfamily,align=right,
  labelsep=\ccwd,labelindent=-\ccwd,leftmargin=*}
\fvset{
  fontsize=\small,baselinestretch=1,numbersep=5pt,
  formatcom=\ctexdocverbaddon,
  listparameters=\setlength\topsep{\MacrocodeTopsep}}
\DefineVerbatimEnvironment{ctexexam}{Verbatim}{%
  gobble=4,
  frame=single,framesep=10pt,
  label=\rule{0pt}{12pt}\textnormal{\bfseries 例 \arabic{ctexexam}},
  listparameters=
    \refstepcounter{ctexexam}\ctexexamlabelref
    \appto\FV@EndList{\nointerlineskip}}
\define@key{FV}{labelref}{\def\ctexexamlabelref{\label{#1}}}
\let\ctexexamlabelref\empty
\newcounter{ctexexam}
\BeforeBeginEnvironment{function}{\par\nointerlineskip}
\AtEndEnvironment{function}
  {\par\xdef\ctexfixprevdepth{\prevdepth=\the\prevdepth\space}}
\AfterEndEnvironment{function}{\ctexfixprevdepth}
\AtBeginEnvironment{syntax}{\linespread{1}}
\preto\MacroFont{\linespread{1}}
\appto\MacroFont{\hyphenchar\font\m@ne\ctexdocverbaddon}
\preto\AltMacroFont{\linespread{1}}
\appto\AltMacroFont{\hyphenchar\font\m@ne\ctexdocverbaddon}
\def\Module#1{\mbox{\normalfont\sffamily\textlangle#1\textrangle}}
\ExplSyntaxOn
\cs_set_protected:Npn \__codedoc_special_index_aux:nnnnn #1#2#3#4#5
  {
    \__codedoc_special_index_set:Nn \l__codedoc_index_escaped_macro_tl {#2}
    \str_if_eq:onTF { \@currenvir } { macrocode }
      { \codeline@wrindex }
      {
        \HD@target
        \index
      }
      {
        \tl_if_empty:nF { #3 #4 }
          { #3 \actualchar #4 \levelchar }
        #1
        \actualchar
        {
          \token_to_str:N \verbatim@font \c_space_tl
          \l__codedoc_index_escaped_macro_tl
        }
        \encapchar
        hdclindex{\the\c@HD@hypercount}{#5}
      }
  }
\DeclareDocumentCommand \cs { O{} m }
  { \__codedoc_cmd_aux:no {#1} { \c__codedoc_backslash_tl #2 } }
\DeclareDocumentCommand \tn { O{} m }
  {
    \__codedoc_cmd_aux:no
      { index = TeX , replace = false , #1 }
      { \c__codedoc_backslash_tl #2 }
  }
\DeclareDocumentCommand \meta { +m }
  { \__codedoc_meta_aux:n {#1} }
\DeclareExpandableDocumentCommand \bookmarkcstn { O{} m }
  { \tl_to_str:n {#2} }
\cs_new:Npn \bookmarkmeta #1 { < \tl_to_str:n {#1} > }
\cs_generate_variant:Nn \__codedoc_cmd_aux:nn { no }
\AtBeginEnvironment { syntax }
  {
    \char_set_active_eq:NN \| \orbar
    \char_set_active_eq:NN \( \defaultvalaux
  }
\ExplSyntaxOff
\pdfstringdefDisableCommands{%
  \let\cs\bookmarkcstn
  \let\tn\bookmarkcstn
  \let\meta\bookmarkmeta}
\def\orbar{\textup{\textbar}}
\def\defaultval#1{\textbf{\textup{#1}}}
\def\defaultvalaux#1){\defaultval{#1}}
\def\TF{true\orbar false}
\def\TTF{\defaultval{true}\orbar false}
\def\TFF{true\orbar\defaultval{false}}
\protected\def\opt{\texttt}
\def\pdfTeX{\hologo{pdfTeX}}
\def\XeTeX{\hologo{XeTeX}}
\def\XeLaTeX{\hologo{XeLaTeX}}
\def\LuaLaTeX{\hologo{LuaLaTeX}}
\def\pdfLaTeX{\hologo{pdfLaTeX}}
\def\LaTeX{\hologo{LaTeX}}
\def\LaTeXe{\hologo{LaTeX2e}}
\def\LTXIII{\hologo{LaTeX3}}
\def\dvipdfmx{DVIPDFM\textit{x}}
\def\ctexkitrev#1{%
  \href{http://code.google.com/p/ctex-kit/source/detail?r=#1}{\texttt{ctex-kit} rev#1}}
\patchcmd\theCodelineNo{\sffamily\tiny}{\normalfont\sffamily\tiny}{}{}
\appto\GlossaryParms{%
  \def\@idxitem{\par\hangindent 2em }%
  \def\subitem{\@idxitem\hspace*{1em}}%
  \def\subsubitem{\@idxitem\hspace*{2em}}}
\patchcmd\l@section{2.5em}{1.5em}{}{}
\patchcmd\l@subsection{2.5em}{1.5em}{}{}
\patchcmd\changes@{\space}{\lbrack}{}{}
\patchcmd\@wrglossary{hdpindex}{hdclindex{\the\c@HD@hypercount}}{}{}
\newenvironment{defaultcapconfig}{%
  \catcode`\%=14 \input{ctexcap-utf8.cfg} \catcode`\%=9 }{}
\makeatother
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\def\glossaryname{版本历史}
\GlossaryPrologue{\section*{\glossaryname}}
\IndexPrologue{%
  \section*{\indexname}
  \textit{意大利体的数字表示描述对应索引项的页码；
  带下划线的数字表示定义对应索引项的代码行号；
  罗马字体的数字表示使用对应索引项的代码行号。}}
\usepackage{makecell}
\begin{document}
  \DocInput{\jobname.dtx}
  \newgeometry{hmargin=15mm,vmargin={25mm,15mm},footskip=7mm}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
%
% \fi
%
% \changes{v2.0}{2014/03/06}{应用 \LTXIII{} 重新整理代码。}
% \changes{v2.0}{2014/03/12}{删除 \file{c19gbsn.fd} 和 \file{c19gkai.fd}。}
%
%
% \CheckSum{4196}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
% \GetFileInfo{\jobname.dtx}%
%
% \title{\bfseries \CTeX{} 宏包说明}
% \author{\href{http://www.ctex.org}{ctex.org}}
% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ctexrevnum}.}}
% \maketitle
%
% \begin{abstract}
% \CTeX{} 宏包是面向中文排版的通用 \LaTeX{} 排版框架，为中文 \LaTeX{} 文档
% 提供了汉字输出支持、标点压缩、字体字号命令、标题文字汉化、中文版式调整、数字
% 日期转换等支持功能，可适应论文、报告、书籍、幻灯片等不同类型的中文文档。
%
% \CTeX{} 宏包支持 \LaTeX{}、\pdfLaTeX{}、\XeLaTeX{}、\LuaLaTeX{} 等多种不同
% 的编译方式，并为它们提供了统一的界面。主要功能由宏包 \pkg{ctex} 或中文文档类
% \cls{ctexart}、\cls{ctexrep}、\cls{ctexbook} 实现。
% \end{abstract}
%
% \tableofcontents
% \clearpage
%
% \begin{documentation}
%
% \section{介绍}
%
% 这个宏包的部分原始代码来自于由王磊编写 \cls{cjkbook} 文档类，还有一小部分原
% 始代码来自于吴凌云编写的 \file{GB.cap} 文件。原来的这些工作都是零零碎碎编写的，没有认
% 真、系统的设计，也没有用户文档，非常不利于维护和改进。2003 年，吴凌云用 \pkg{doc} 和
% \pkg{DocStrip} 工具重新编写了整个文档，并增加了许多新的功能。2007 年，oseen 和王越在
% \CTeX{} 宏包基础上增加了对 UTF-8 编码的支持，开发出了 \pkg{ctexutf8} 宏包。
% 2009 年 5 月，我们在 Google Code 建立了 ctex-kit 项目^^A
% \footnote{\url{http://code.google.com/p/ctex-kit/}}，对 \CTeX{} 宏包及相关
% 宏包和脚本进行了整合，并加入了对 \XeTeX{} 的支持。在开发新版本时，考虑到合作开发和
% 调试的方便，我们不再使用 \pkg{doc} 和 \pkg{DocStrip} 工具，改为直接编写宏包文件。
% 2014 年 3 月，为了适应 \LaTeX{} 的最新发展，特别是 \LTXIII{} 的逐渐成熟，李清用
% \LTXIII{} 重构了整个宏包的代码，并重新使用 \pkg{doc} 和 \pkg{DocStrip} 工具进行代码
% 的管理，升级版本号为 2.0。
%
% 最初 Knuth 设计开发 \TeX{} 的时候没有考虑到支持多国语言，特别是多字节的中日韩
% 语言。这使得 \TeX{} 以至后来的 \LaTeX{} 对中文的支持一直不是很好。即使在
% \pkg{CJK} 宏包解决了中文字符处理的问题以后，中文用户使用 \LaTeX{} 仍然要面对许
% 多困难。最常见的就是中文化的标题。由于中文习惯和西方语言的不同，使得很难直接使
% 用原有的标题结构来表示中文标题，因此需要对标准 \LaTeX{} 宏包做较大的修改。此
% 外，还有诸如日期格式、首行缩进、中文字号的对应关系等等细节问题。\CTeX{} 宏
% 包正是为着解决这些 \LaTeX{} 文档中文化问题而产生的。另一方面，随着 \TeX{} 引擎
% 和 \LaTeX{} 宏包的不断开发，在 \LaTeX{} 中支持中文字符的方式也由早期的
% \pkg{CCT} 这类单一的专用系统发展为 \pdfTeX{} 引擎下的 \pkg{CJK}、\pkg{zhmCJK}
% 宏包、\XeTeX{} 引擎下的 \pkg{xeCJK} 宏包、\LuaTeX{} 引擎下的 \pkg{luatexja} 宏
% 包等多种方式，各种方式下都有不同的适用范围和用法细节，不同操作系统和语言环境
% 也带来不少细节差异，亟需一个统一的界面来访问不同的中文处理方式，使同一份文档能
% 在不同的环境下交换使用。\CTeX{} 宏包也在统一中文处理界面上做出了努力。
%
% 实现 \CTeX{} 宏包中间很多地方用到了在 \url{bbs.ctex.org} 论坛上的讨论结果，
% 在此对参与讨论的朋友们表示感谢。
%
%
% \section{简明教程}
%
% \subsection{使用 \CTeX{} 文档类}
%
% \CTeX{} 宏包的使用十分简单。对于使用 \LaTeX{} 标准文档类
% \cls{article}、\cls{report}、\cls{book} 的用户，希望通过 \CTeX{} 宏包实现中文
% 及中文版式的支持，只需用 \cls{ctexart}、\cls{ctexrep} 或者 \cls{ctexbook} 替
% 换原有的文档类即可。
%
% \subsubsection{使用 \XeLaTeX{} 或 \LuaLaTeX{} 编译}
%
% 使用 \XeLaTeX{} 或 \LuaLaTeX{} 编译时，必须将涉及到的所有源文件使用 UTF-8
% 编码保存。
%
% \begin{ctexexam}
%   \documentclass{ctexart}
%   \begin{document}
%   中文文档类测试，保存为 UTF-8 编码，使用 XeLaTeX 或 LuaLaTeX 编译。
%   \end{document}
% \end{ctexexam}
%
% \subsubsection{使用 \LaTeX{} 或 \pdfLaTeX{} 编译}
%
% 在默认情况下，使用 \LaTeX{} 或 \pdfLaTeX{} 编译时，需将涉及到的涉及到的所有
% 源文件使用 GBK 编码保存。
%
% \begin{ctexexam}
%   \documentclass{ctexart}
%   \begin{document}
%   中文文档类测试，保存为 GBK 编码，使用 LaTeX 或 pdfLaTeX 编译。
%   \end{document}
% \end{ctexexam}
%
% 为 \CTeX{} 宏包或文档类添加 \opt{UTF8} 选项，则使用 \LaTeX{} 或 \pdfLaTeX{}
% 编译时，也可以让 \CTeX{} 宏包或文档类在 UTF-8 模式下工作。
%
% \begin{ctexexam}
%   \documentclass[UTF8]{ctexart}
%   \begin{document}
%   中文文档类测试，保存为 UTF-8 编码，使用 LaTeX 或 pdfLaTeX 编译。
%   \end{document}
% \end{ctexexam}
%
% \subsection{使用其他文档类}
%
% 对于 \cls{article}、\cls{report}、\cls{book} 之外的文档类，则可以载入
% \pkg{ctex} 包来使用 \CTeX{} 宏包。
%
% 例如，编写中文的 \cls{beamer} 演示，就可以使用：
% \begin{ctexexam}
%   \documentclass{beamer}
%   \usepackage{ctex}
%   \begin{document}
%   \begin{frame}{中文演示文档}
%   \begin{itemize}
%     \item 保存为 UTF-8 编码，使用 XeLaTeX 或 LuaLaTeX 编译。
%     \item 保存为 GBK 编码，使用 LaTeX 或 pdfLaTeX 编译。
%   \end{itemize}
%   \end{frame}
%   \end{document}
% \end{ctexexam}
% 这里，\pkg{ctex} 包也可以加上 \opt{UTF8} 选项指定文档编码。
%
% 如果使用的文档类本身还是基于 \LaTeX{} 标准文档类生成的，则还可以给
% \pkg{ctex} 包加上 \opt{heading} 选项，设置其章节标题的格式。
% \begin{ctexexam}
%   \documentclass{ltxdoc}
%   \usepackage[UTF8,heading]{ctex}
%   \begin{document}
%   \section{简介}
%   中文化的 \LaTeX{} 手册。
%   \end{document}
% \end{ctexexam}
%
% \section{参考手册}
%
% \CTeX{} 宏包会根据用户使用的编译方式\footnote{\LaTeX、\pdfLaTeX、\XeLaTeX 以及
% \LuaLaTeX。}在底层选择不同的中文支持方式（见表 \ref{tab:chinese-support}）。
%
% \begin{table}[htb]
% \centering
% \begin{tabular}{ccc}
%   \toprule
%   (pdf)\LaTeX & \XeLaTeX & \LuaLaTeX \\
%   \midrule
%   \pkg{CJK} & \pkg{xeCJK} & \pkg{luatexja} \\
%   \bottomrule
% \end{tabular}
% \caption{\CTeX{} 宏包的中文支持方式}
% \label{tab:chinese-support}
% \end{table}
%
% \CTeX{} 宏包在用户使用 \XeLaTeX{} 及 \LuaLaTeX{} 编译时，使用（且仅能
% 使用）UTF-8 编码；而因为历史原因，在用户使用 \LaTeX{} 及 \pdfLaTeX{} 编译
% 时默认使用 GBK 编码。除非有特殊的需求，我们推荐用户使用 UTF-8 编码，并使用
% \XeLaTeX{} 或 \LuaLaTeX{} 编译。
%
% \subsection{依赖与安装}
%
% \CTeX{} 是一个 \LaTeX{} 宏包，只有一个源文件 \file{ctex.dtx}。它依赖下列宏包：
%
% \begin{itemize}
%   \item \pkg{expl3}、\pkg{xparse} 和 \pkg{l3keys2e} 宏包。它们属于 \pkg{l3kernel}
%   和 \pkg{l3packages} 集合，并依赖
%   \begin{itemize}
%     \item \pkg{etex} 宏包。
%   \end{itemize}
%   \item \pkg{ifpdf} 宏包，属于 \pkg{oberdiek} 集合。
%   \item \pkg{etoolbox} 宏包。
%   \item \pkg{everysel} 宏包，属于 \pkg{ms} 集合。
%   \item \pkg{zhnumber} 宏包。
%   \item[$\Rightarrow$] 以上是各种编译方式都必需的依赖项。
%   \item \pkg{CJK} 集合，它的下划线功能依赖 \pkg{ulem} 宏包。
%   \item \pkg{CJKpunct} 宏包。
%   \item \pkg{zhmetrics} 宏包。
%   \item \pkg{zhmCJK} 宏包。
%   \item[$\Rightarrow$] 以上是使用 \pdfLaTeX{} 或 \LaTeX{} + \dvipdfmx{} 的编译方式所需要
%   的依赖项，其中 \pkg{zhmCJK} 是可选的。
%   \item \pkg{xeCJK} 宏包，它还依赖
%   \begin{itemize}
%     \item \pkg{fontspec} 宏包，它还依赖
%     \begin{itemize}
%       \item \pkg{euenc} 宏包。
%       \item \pkg{xunicode} 宏包，它还依赖 \pkg{tipa} 宏包。
%     \end{itemize}
%     \item \pkg{everypage} 宏包。
%   \end{itemize}
%   \item[$\Rightarrow$] 以上是使用 \XeLaTeX{} 编译时的依赖项。
%   \item \pkg{luatexja} 集合，它还依赖
%   \begin{itemize}
%     \item \pkg{luaotfload} 宏包，它还依赖 \pkg{luatexbase} 宏包。
%     \item \pkg{xkeyval} 宏包。
%   \end{itemize}
%   \item[$\Rightarrow$] 以上是使用 \LuaLaTeX{} 编译时的依赖项。
% \end{itemize}
%
% \CTeX{} 正式发布的版本和依赖的各个宏包或者集合都会被发行版 \TeX{} Live 或者
% \hologo{MiKTeX} 收录，可以直接用它们提供的宏包管理器安装或者更新，不需要自行
% 下载安装。
%
% ^^A FIXME: zhmCJK 的安装
%
% \subsection{\CTeX{} 宏包与文档类}
%
% \CTeX{} 宏包的组成见表 \ref{tab:ctex}。
%
% \begin{table}[htb]
% \centering
% \begin{tabularx}{\linewidth}{l>{\ttfamily}lX}
% \toprule
%   类别   & \textrm{文件} & 说明 \\
% \midrule
%   文档类 & ctexart.cls   & 标准文档类 \cls{article} 的中文化版本，一般适用于
%                            短篇幅的文章 \\
%          & ctexrep.cls   & 标准文档类 \cls{report} 的中文化版本，一般适用于
%                            中篇幅的报告 \\
%          & ctexbook.cls  & 标准文档类 \cls{book} 的中文化版本，一般适用于
%                            长篇幅的书籍 \\
% \midrule
%   格式   & ctex.sty      & 提供全部功能，但\emph{默认不开启章节标题设置功能}，
%                            需要使用 \opt{heading} 选项来开启 \\
% \bottomrule
% \end{tabularx}
% \caption{\CTeX{} 宏包的组成}\label{tab:ctex}
% \end{table}
%
% 除此以外，\CTeX{} 宏包定义和调整中文字号的功能被提取到 \file{ctexsize.sty} 当中，
% 可以在 \CTeX{} 之外调用 \pkg{ctexsize} 宏包使用该功能。它可以使用随后介绍的宏包
% 选项 \opt{cs4size}、\opt{c5size} 和命令 \cs{zihao}。
%
% 我们推荐用户直接使用 \CTeX{} 宏包提供的三个中文文档类，而不是在使用 \LaTeX{}
% 标准文档类的基础上，再使用 \pkg{ctex} 宏包。\pkg{ctex} 宏包被设计为适配非标准
% 文档类（例如 \cls{beamer} 文档类）；而它的 \opt{heading} 选项则被设计为适配
% 衍生自标准文档类的文档类（例如 \cls{ltxdoc} 文档类）。
%
% \subsection{宏包选项}
% \label{subs:options}
%
% 宏包的选项用于改变一些默认的设置。\CTeX{} 宏包和文档类的默认设置已经对中文
% 行文和排版习惯做了尽可能的配置，因此除非必要，普通用户应尽量避免对默认设置的修改。
% 如果你觉得某些默认设置不合适，或者需要增减选项，可以在项目主页上^^A
% \href{https://code.google.com/p/ctex-kit/issues/entry}{提交 issue}，
% 向我们反映，我们会酌情在后续版本中予以改进。
%
% \CTeX{} 宏包有部分选项以 \meta{key}|=|\meta{value} 的形式提供，剩余部分
% 是传统的选项。你应该在调用宏包的时候直接设置这些选项。在下面的说明中使用^^A
% \textbf{粗体}来表示 \CTeX{} 的默认设置。
%
% \CTeX{} 文档类基于 \LaTeX{} 的标准文档类。因此，它们除了可以使用下面介绍的
% 选项之外，还能够使用标准文档类的选项。例如，设置纸张大小和方向的
% \opt{a4paper} 和 \opt{landscape}，设置单双面的 \opt{oneside} 和
% \opt{twoside} 等。\CTeX{} 会将这些选项传给标准文档类^^A
% \footnote{事实上，\LaTeX{} 在文档类中的选项是全局设定的，除了对使用的文档类有
% 影响外，也可能会影响到随后使用的宏包。如果这些宏包中有某些选项出现在文档类的
% 选项列表中，那么该选项将会被自动激活。}。
%
%
% \subsubsection{默认字号选项}
% \label{subsubs:options-class}
%
% \begin{function}{cs4size, c5size}
%   分别使用小四号字或五号字作为默认字体大小。\CTeX{} 默认设置 \opt{c5size}。
%   这两个选项在 \pkg{ctexsize} 宏包中也有定义。
% \end{function}
%
% \begin{function}{10pt, 11pt, 12pt}
%   可以使用标准文档类的同类选项（\opt{10pt}、\opt{11pt} 和 \opt{12pt}）
%   抑制中文字号设置。
% \end{function}
%
% \opt{cs4size} 和 \opt{c5size} 选项还会将标准文档类中的字体大小命令调整为
% 中文字号（见表 \ref{tab:fontsize}）。
%
% \begin{table}[htb]
% \centering
% \setlength\tabcolsep{1em}
% \begin{tabular}{l*2{c>{\ttfamily}r}*3{>{\ttfamily}c}}
% \toprule
% & \multicolumn2c{|c5size|} & \multicolumn2c{|cs4size|} &
% \multicolumn1c{|10pt|} & \multicolumn1c{|11pt|} & \multicolumn1c{|12pt|} \\
% \cmidrule(lr){2-3} \cmidrule(lr){4-5}
% \cmidrule(lr){6-6} \cmidrule(lr){7-7} \cmidrule(lr){8-8}
% 字体命令        & 字号 & \textrm{bp} & 字号 & \textrm{bp}
%  & \textrm{pt} & \textrm{pt} & \textrm{pt} \\
% \midrule
% |\tiny|         & 七号 & 5.5  & 小六 & 6.5  & ~5 & ~6 & ~6 \\
% |\scriptsize|   & 小六 & 6.5  & 六号 & 7.5  & ~7 & ~8 & ~8 \\
% |\footnotesize| & 六号 & 7.5  & 小五 & 9~~  & ~8 & ~9 & 10 \\
% |\small|        & 小五 & 9~~  & 五号 & 10.5 & ~9 & 10 & 11 \\
% |\normalsize|   & 五号 & 10.5 & 小四 & 12~~ & 10 & 11 & 12 \\
% |\large|        & 小四 & 12~~ & 小三 & 15~~ & 12 & 12 & 14 \\
% |\Large|        & 小三 & 15~~ & 小二 & 18~~ & 14 & 14 & 17 \\
% |\LARGE|        & 小二 & 18~~ & 二号 & 22~~ & 17 & 17 & 20 \\
% |\huge|         & 二号 & 22~~ & 小一 & 24~~ & 20 & 20 & 25 \\
% |\Huge|         & 一号 & 26~~ & 一号 & 26~~ & 25 & 25 & 25 \\
% \bottomrule
% \end{tabular}
% \caption{标准字体命令与字号的对应}\label{tab:fontsize}
%\end{table}
%
% \subsubsection{中文标题选项}
% \label{subsubs:options-heading}
%
% \begin{function}{heading}
%   \begin{syntax}
%     heading = <\TFF>
%   \end{syntax}
%   是否启用 \pkg{ctex.sty} 宏包的标题格式设置功能。参见
%   \ref{subsubs:secstyle}~节。
% \end{function}
%
% \CTeX{} 宏包提供的三个文档类总是启用中文标题设置功能。\opt{heading} 选项
% 只在 \pkg{ctex.sty} 下有意义。如果在 \pkg{ctex.sty} 下启用该选项，将会检查使用
% 的是否为 \LaTeX{} 标准文档类。若是，则该选项将会使得 \pkg{ctex.sty} 宏包的行为
% 和 \CTeX{} 宏包提供的三个中文文档类\emph{完全}一致；否则，会根据 \cs{chapter}
% 是否有定义来使用 \cls{ctexbook} 或者 \cls{ctexart} 的标题设置。
%
% \begin{function}{sub3section}
%   将 \cs{paragraph} 标题改为类似 section 的格式（感觉类似
%   \cs{subsubsubsection}），即标题单独占一行。此时 \cs{subparagraph} 命令产生
%   的标题会具有原本 \cs{paragraph} 的格式。
%
%   具体格式可参考 \ref{subsubs:secstyle}~节中 \opt{afterskip} 等选项。
%
%   此选项通常需要配合将计数器 |secnumdepth| 的值为设置为 4。
% \end{function}
%
% \begin{function}{sub4section}
%   将 \cs{paragraph} 和 \cs{subparagraph} 都改为 section 类的格式（感觉类似
%   \cs{subsubsubsubsection}），即标题单独占一行。
%
%   具体格式可参考 \ref{subsubs:secstyle}~节中 \opt{afterskip} 等选项。
%
%   此选项通常需要配合将计数器 |secnumdepth| 的值为设置为 4 或 5。
% \end{function}
%
% 这两个选项在文档类和启用 \opt{heading} 的 \pkg{ctex.sty} 下才有意义。
%
% \subsubsection{中文编码选项}
%
% 下面的选项用于选择 \CTeX{} 宏包内部的编码，以匹配用户编写文档使用的编码。
%
% \begin{function}{GBK, UTF8}
%   使用 (pdf)\LaTeX{} 编译时，\CTeX{} 的默认编码是 GBK。此时可以使用 UTF8 选项
%   将默认编码改为 UTF-8。而使用 \XeLaTeX{} 或 \LuaLaTeX{} 编译时，\CTeX{} 内部
%   总是使用 UTF-8 编码，所以不必指明这些选项。
% \end{function}
%
% \subsubsection{中文字库选项}
% \label{subsubs:options-CJK-font}
%
% 默认情况下，\CTeX{} 宏包会根据用户使用的操作系统\footnote{\CTeX{} 宏包现在
% 能够识别 Mac OS X 系统以及 Windows 系统。}自动选择设置的字体（见表
% \ref{tab:default-font-select}）。
%
% 需要注意的是，在 \pdfTeX{} 引擎下，\CTeX{} 的默认字体设置只支持 \pdfLaTeX{} 或者
% \LaTeX{} + \dvipdfmx{} 的编译方式。如果需要使用 Dvips，就需要将下面介绍的
% \opt{fontset} 选项设置为 \opt{none}，然后按照传统方式^^A
% \footnote{可以使用 \pkg{zhmetrics} 宏包提供的脚本
%   \href{http://ctex-kit.googlecode.com/svn/trunk/zhmetrics/CTeXFonts.lua}
%        {\file{CTeXFonts.lua}}。}^^A
% 在本地安装好 CJK 字体。
%
% Mac OS X 系统下的华文字体在 (pdf)\LaTeX{} 下
% 不可用，只支持 \XeLaTeX{} 或者 \LuaLaTeX{} 的编译方式。Fandol 在 \pdfLaTeX{}
% 下不可用。
%
% \begin{table}[htb]
% \centering
% \begin{tabular}{ccc}
%   \toprule
%   Mac OS X & Windows & 其他\\
%   \midrule
%   华文字体 & 中易字体 & Fandol 字体 \\
%   \bottomrule
% \end{tabular}
% \caption{\CTeX{} 宏包在默认选项下的字体}
% \label{tab:default-font-select}
% \end{table}
%
% 通常，由 \CTeX{} 宏包进行的自动配置已经足够使用，无需用户手工干预；但
% 是 \CTeX{} 仍然提供了一系列选项，供在 \CTeX{} 的自动选择机制因为
% 意外情况失效，或者在用户有特殊需求的情况下使用。\emph{除非必要，用户不
% 应使用这些选项。}
%
% \begin{function}{zhmap}
%   \begin{syntax}
%     zhmap = <\TTF|zhmCJK>
%   \end{syntax}
%   是否使用 \pkg{zhmetrics} 宏包提供的字体映射机制，将 \pkg{CJK} 中文字库通过
%   \cs{special} 命令映射到对应的 \texttt{.ttf} 字体文件。
% \end{function}
%
%   \opt{zhmCJK} 还将载入 \pkg{zhmCJK} 宏包。它基于 \pkg{zhmetrics} 机制和
%   \pkg{CJK} 宏包，提供了与 \pkg{xeCJK} 类似的用户界面，可以很方便的完成字体
%   安装设置工作。
%
%   如果需要使用自定义的字体映射文件，或者希望使用 Type1 字库，请禁用本选项。
%   此时，将会使用传统的字体映射机制，调用系统中的字体映射文件。
%
%   本选项只在使用 (pdf)\LaTeX{} 编译时有意义。
%
% \begin{function}{fontset}
%   \begin{syntax}
%     fontset = <none|adobe|fandol|founder|mac|ubuntu|windows|...>
%   \end{syntax}
%   如果没有指定 \opt{fontset} 的值，\CTeX{} 宏包会根据用户使用的操作系统
%   配置相应的字体。目前 \CTeX{} 能够识别 Mac OS X 和 Windows 系统。
% \end{function}
%
% \CTeX{} 预定义了以下六种中文字库。它们之中除了 \opt{windows}，在使用
% (pdf)\LaTeX 编译但没有启用 \opt{zhmap} 选项都没有定义，都会返回错误。
% 此时对于 \opt{windows} 来说，假设已经按照传统方式在本地安装好了
% CJK 字体。
%
% \begin{optdesc}
%   \item[adobe] 使用 Adobe 公司的四款中文字体，不支持 \pdfLaTeX。
%   \item[fandol] 使用 Fandol 中文字体\footnote{由马起园、苏杰、黄晨成等人开发
%   的开源中文字体，参见：\url{https://github.com/clerkma/fandol-fonts}。}，
%   不支持 \pdfLaTeX。
%   \item[founder] 使用方正公司的中文字体。
%   \item[mac] 使用 Mac OS X 系统下的华文字体，只能用于 \XeLaTeX{} 和 \LuaLaTeX。
%   \item[ubuntu] 使用 Ubuntu 系统下的文泉驿和文鼎字体。
%   \item[windows] 使用简体中文 Windows 系统下的中易字体。
% \end{optdesc}
%
% 如果不想使用 \CTeX{} 预定义的中文字库，可以设置 \opt{fontset} 为下述值之一。
%
% \begin{optdesc}
%   \item[none] 不配置中文字体，需要用户自己配置。
%   \item[\meta{name}] 这里 \meta{name} 为自定义的名字。
%   \CTeX{} 宏包将载入名为 |ctex-fontset-|\meta{name}|.def| 的文件作为字体配置
%   文件。因此，请先保证文件的存在。可以在当前工作目录或者本地 \texttt{TDS} 目录
%   树下合适位置建立一个名为 |ctex-fontset-|\meta{name}|.def| 的文件，在这个文件
%   里面自定义中文字体。然后通过使用 |fontset=|\meta{name} 选项来调用它。字体配置
%   文件的具体写法可以参考 \CTeX{} 宏包 \texttt{fontset} 目录下的字体配置文件。
% \end{optdesc}
%
% \subsubsection{排版风格选项}
% \label{subsubs:options-type-style}
%
% \begin{function}{cap}
%   \begin{syntax}
%     cap = <\TTF>
%   \end{syntax}
%   是否对标题中英文文字进行汉化（如“图”、“表”、“目录”、“参考文献”等，
%   见 \ref{subsubs:capname}~节）并设置章节标题的中文化格式（见
%   \ref{subsubs:secstyle}~节）。
%
%   \opt{cap} 选项控制的标题汉化总是生效的，而对章节标题的中文化格式设定仅在
%   \opt{heading} 选项（\ref{subsubs:options-heading}~节）打开时生效。
% \end{function}
%
% \begin{function}{punct}
%   \begin{syntax}
%     punct = <(quanjiao)|banjiao|kaiming|CCT|plain>
%   \end{syntax}
%   设置标点处理格式。预定义好的格式有：
% \end{function}
%
%   \begin{optdesc}
%     \item[quanjiao] 全角式：所有标点占一个汉字宽度，相邻两个标点占 1.5 汉字宽度；
%     \item[banjiao]  半角式：所有标点占半个汉字宽度；
%     \item[kaiming]  开明式：句末点号用全角，其他半角；
%     \item[CCT]   CCT 格式：所有标点符号的宽度略小于一个汉字宽度；
%     \item[plain] 原样（不调整标点间距）。
%   \end{optdesc}
%
% \begin{function}{space}
%   \begin{syntax}
%     space = <\TF|(auto)>
%   \end{syntax}
%   用于控制是否忽略汉字后面的空格。
% \end{function}
%
%   \begin{optdesc}
%     \item[true] 保留汉字后面的空格，类似英文的习惯。这时用户需要自己处理由换行
%     产生的空格（在行尾加上 |%| 可以避免），否则排版结果可能不符合中文习惯。
%     \item[false] 总是忽略掉汉字后面的空格。只在使用 (pdf)\LaTeX{} 编译时有意义。
%     不建议使用该选项。
%     \item[auto] 根据空格后面的情况决定是否保留：如果空格后面是汉字，则忽略该
%     空格，否则保留。
%   \end{optdesc}
%
%   \emph{使用 \LuaLaTeX{} 编译的时候，该选项无效：汉字间的空格以及汉字与西文字符
%   之间的空格总是有效，不会被忽略，但可以自动忽略掉由换行产生的空格。}
%
% \begin{function}{linespread}
%   \begin{syntax}
%     linespread = <数值>
%   \end{syntax}
%   接受一个浮点数值，用于调整行距。初始值为 1.3，即设置基线距离
%   （\cs{baselineskip}）为 $1.3\times 1.2=1.56$ 倍字体大小。
% \end{function}
%
% \begin{function}{autoindent}
%   \begin{syntax}
%     autoindent = <\TTF>
%   \end{syntax}
%   在字体大小发生变化时，是否自动调整段首缩进（\cs{parindent}）的大小。
% \end{function}
%
% \subsubsection{宏包兼容选项}
%
% \begin{function}{fancyhdr}
%   \begin{syntax}
%     fancyhdr = <\TFF>
%   \end{syntax}
%   保持和 \pkg{fancyhdr} 宏包的兼容性。启用该选项将自动调用 \pkg{fancyhdr} 宏包。
% \end{function}
%
% \begin{function}{fntef}
%   \begin{syntax}
%     fancyhdr = <\TFF>
%   \end{syntax}
%   启用该选项将自动调用 \pkg{CJKfntef} 或 \pkg{xeCJKfntef} 宏包。
% \end{function}
%
% \begin{function}{hyperref}
%   \begin{syntax}
%     fancyhdr = <\TFF>
%   \end{syntax}
%   自动判断 \pkg{hyperref} 宏包的正确参数以避免产生乱码。如果在导言区用户没有自
%   己调用 \pkg{hyperref}，则该选项将使得 \pkg{hyperref} 宏包在导言区末尾被自动
%   调用；如果需要对 \pkg{hyperref} 宏包做进一步的设置，则用户可以自己
%   在 \CTeX{} 宏包后使用 \cs{hypersetup} 命令进行适当设置。
% \end{function}
%
% \subsection{格式控制命令 \cs{ctexset}}
%
% \CTeX{} 宏包为用户提供了一个通用的文档框架，使得用户可以根据需求，自由地在
% 底层不同的中文支持方式之间切换。为此，我们定义了一些命令，使得用户可以用统一
% 的方式对文档进行控制。
%
% \begin{function}{\ctexset}
%   \begin{syntax}
%     \cs{ctexset} \Arg{键值列表}
%   \end{syntax}
% 是 \CTeX{} 宏包的通用控制命令，用来在宏包载入后控制宏包的各项功能。
% \cs{ctexset} 的参数是一个键值列表，以通用的接口完成各项设置。如非特别说明，
% 后文介绍的所有选项都使用 \cs{ctexset} 命令进行设置。
% \end{function}
%
% \cs{ctexset} 的参数是一组由逗号分隔的选项列表，列表中的选项通常是一个
% \meta{key}|=|\meta{value} 格式的定义。例如设置摘要与参考文献标题名称
% （\ref{subsubs:capname}~节）就可以使用：
% \begin{ctexexam}[labelref=exam:capname]
%   \ctexset{
%     abstractname={本文概要},
%     bibname={文\quad 献}
%   }
% \end{ctexexam}
%
% \cs{ctexset} 采用 \LaTeX3 风格的键值设置，因此支持不同类型的选项与层次化的选
% 项设置，相关示例见 \ref{subsubs:secstyle}~节。
%
% \subsection{中文文字支持}
%
% \CTeX{} 宏包为用户提供了一个通用的文档框架，使得用户可以根据需求，自由地在
% 底层不同的中文支持方式之间切换。因此，一份文档可以几乎不做修改地在不同的操作
% 系统设置、不同的 \TeX{} 引擎下编译，正常地输出中文文档，而无须考虑具体的底层
% 细节。
%
% 在不同的操作系统设置与 \TeX{} 引擎下，\CTeX{} 宏包需要在底层使用不同的中文支
% 持宏包，它们的字体、字号和文字修饰的命令可能各不相同。为此，我们定制了一些命
% 令，使得用户可以用统一的方式对文档中的文字格式进行控制。
%
% \subsubsection{中文字体命令}
%
% \CTeX{} 宏包预定义的中文字库基本上都定义了以下四种常用的中文字体命令。
%
% \begin{optdesc}
%   \item[\cs{songti}] 宋体，CJK 等价命令 |\CJKfamily{zhsong}|。
%   \item[\cs{heiti}] 黑体，CJK 等价命令 |\CJKfamily{zhhei}|。
%   \item[\cs{fangsong}] 仿宋，CJK 等价命令 |\CJKfamily{zhfs}|。
%   \item[\cs{kaishu}] 楷书，CJK 等价命令 |\CJKfamily{zhkai}|。
% \end{optdesc}
%
% 需要注意的是 \cs{fangsong} 在 \opt{ubuntu} 字库下没有定义。而在
% \opt{windows} 和 \opt{founder} 字库下，还有 \cs{lishu} 和 \cs{youyuan}。
%
% \begin{optdesc}
%   \item[\cs{lishu}] 隶书，CJK 等价命令 |\CJKfamily{zhli}|。
%   \item[\cs{youyuan}] 圆体，CJK 等价命令 |\CJKfamily{zhyou}|。
% \end{optdesc}
%
% 在 \opt{windows} 字库下，还有 \cs{yahei}。
%
% \begin{optdesc}
%   \item[\cs{yahei}] 微软雅黑，CJK 等价命令 |\CJKfamily{zhyahei}|。
% \end{optdesc}
%
% \subsubsection{字号与间距}
%
% \begin{function}{\zihao}
%   \begin{syntax}
%     \cs{zihao} \Arg{字号}
%   \end{syntax}
%   用于调整字号大小。其中 \meta{字号} 的有效值共有 16 个，如表 \ref{tab:zihao}
%   所示。使用 \cs{zihao} 命令调整字体大小时，西文字号大小会始终和中文字号保持一致。
% \end{function}
%
% \begin{table}[htb]
% \centering
% \catcode`*\active
% \def*{\phantom{.}}
% \def~{\phantom{0}}
% \tabcolsep=1em
% \begin{tabular}{>{\ttfamily}ccl}
% \toprule
% $\meta{字号}$ & 大小(bp) & 意义 \\
% \midrule
% ~0   & 42*~ & \zihao{0}    初号    \\
% -0   & 36*~ & \zihao{-0}   小初号  \\
% ~1   & 26*~ & \zihao{1}    一号    \\
% -1   & 24*~ & \zihao{-1}   小一号  \\
% ~2   & 22*~ & \zihao{2}    二号    \\
% -2   & 18*~ & \zihao{-2}   小二号  \\
% ~3   & 16*~ & \zihao{3}    三号    \\
% -3   & 15*~ & \zihao{-3}   小三号  \\
% ~4   & 14*~ & \zihao{4}    四号    \\
% -4   & 12*~ & \zihao{-4}   小四号  \\
% ~5   & 10.5 & \zihao{5}    五号    \\
% -5   & ~9*~ & \zihao{-5}   小五号  \\
% ~6   & ~7.5 & \zihao{6}    六号    \\
% -6   & ~6.5 & \zihao{-6}   小六号  \\
% ~7   & ~5.5 & \zihao{7}    七号    \\
% ~8   & ~5*~ & \zihao{8}    八号    \\
% \bottomrule
% \end{tabular}
% \caption{中文字号}\label{tab:zihao}
% \end{table}
%
% \begin{function}{\ziju}
%   \begin{syntax}
%     \cs{ziju} \Arg{中文字符宽度的倍数}
%   \end{syntax}
%   用于调整相邻汉字之间的间距，即（在正常中文行文中）前一个汉字的右边缘与后一个汉字
%   的左边缘之间的距离。其中参数可以是任意浮点数值；而中文字符宽度指的是实际汉字的
%   宽度，不包含当前字距。
%
%   这个命令会影响 \cs{ccwd} 的值，但不会影响英文字距。
% \end{function}
%
% \begin{function}{\ccwd}
%   当前汉字的字宽保存在长度寄存器 \cs{ccwd} 之中。汉字字宽是相邻两个汉字中心
%   之间的距离，包含字距在内。因此修改字距会间接修改字宽。
% \end{function}
%
% \begin{function}{\CTEXsetfont}
%   更新当前的中文字体信息，包括当前字距（\cs{ccwd}）和段首缩进（\cs{parindent}）。
%   一般来说，用户无需使用这个命令。
% \end{function}
%
% \begin{function}{space}
% ^^A FIXME
% \end{function}
%
% \begin{function}{autoindent}
% ^^A FIXME
% \end{function}
%
% \begin{function}{linespread}
% ^^A FIXME
% \end{function}
%
% \begin{function}{linestretch}
% ^^A FIXME
% \end{function}
%
% \subsection{文档汉化与中文版式}
%
% \subsubsection{中文数字转换}
%
% \CTeX{} 宏包的中文数字转换功能实际上是调用 \pkg{zhnumber} 宏包来完成。下面只
% 介绍一些基本的用法，更高级的用法可以查阅 \pkg{zhnumber} 宏包的文档。
%
% \begin{function}{\chinese}
%   \begin{syntax}
%     \cs{chinese} \Arg{counter}
%   \end{syntax}
%   \cs{chinese} 命令与 \cs{roman} 等命令的用法类似，作用在一个 \LaTeX{}
%   计数器上，将计数器的值以中文数字的形式输出。
% \end{function}
%
% \begin{function}{\zhnumber}
%   \begin{syntax}
%     \cs{zhnumber} \Arg{number}
%   \end{syntax}
%   以中文格式输出数字。这里的数字可以是整数、小数和分数。
% \end{function}
%
% \begin{function}{\zhdigits}
%   \begin{syntax}
%     \cs{zhdigits} \Arg{number}
%   \end{syntax}
%   将阿拉伯数字转换为中文数字串。
% \end{function}
%
% \begin{function}{\CTEXnumber}
%   \begin{syntax}
%     \cs{CTEXnumber} "\"<macro> \Arg{number}
%   \end{syntax}
%   |\|<macro> 必须是一个 \TeX{} 宏，不需预先定义。\cs{CTEXnumber} 通过
%   \cs{zhnumber} 将 \meta{number} 转为中文数字，最后将结果存储在 |\|<macro>
%   里。对 |\|<macro> 的定义是局部的，将它展开一次就可以得到转换结果。
% \end{function}
%
% 一般来说，并不需要使用 \cs{CTEXnumber}，直接使用 \cs{zhnumber} 即可。但是，如果
% 在文档中需要多次使用同一个数字 \meta{number} 的中文形式，就可以先用
% \cs{CTEXnumber} 将结果保存起来备用，而不是每次使用时都用 \cs{zhnumber} 现场
% 转换一次。
%
% \begin{function}{\CTEXdigits}
%   \begin{syntax}
%     \cs{CTEXdigits} "\"<macro> \Arg{number}
%   \end{syntax}
%   \cs{CTEXdigits} 与 \cs{CTEXnumber} 类似，但其转换的结果是中文数字串，而不是
%   中文数字。
% \end{function}
%
% \subsubsection{日期汉化}
%
% \CTeX 宏包对显示当前日期的 \cs{today} 命令进行了汉化，使之以中文的方式显示今
% 天的日期。如编译本文档的日期就是“\today”。
%
% \begin{function}{today}
%   \begin{syntax}
%     today = <(small)|big|old>
%   \end{syntax}
% 该选项用来控制 \cs{today} 命令的输出格式：
% \begin{optdesc}
%   \item[small] \ctexset{today=small}
%     效果为“\today”。使用阿拉伯数字和汉字的日期格式。
%   \item[big] \ctexset{today=big}
%     效果为“\today”。使用全汉字的日期格式。
%   \item[old] \ctexset{today=old}
%     效果为“\today”。使用文档原来的（英文）日期格式。
% \end{optdesc}
% \end{function}
%
% 设置日期格式使用 \cs{ctexset} 命令完成，例如设置全汉字的日期格式：
% \begin{ctexexam}
%   \ctexset{today=big}
% \end{ctexexam}
%
% \CTeX 宏包的中文日期功能实际上也是调用 \pkg{zhnumber} 宏包完成的。如果需要更
% 多有关日期、时间的命令和更复杂的设置，可以查阅 \pkg{zhnumber} 宏包的文档。
%
% \subsubsection{文档标题汉化}
% \label{subsubs:capname}
%
% 这里主要介绍由宏包 \opt{cap} 选项（\ref{subsubs:options-type-style}~节）控制
% 的文档标题汉化功能。
%
% 设置文档标题名的示例可见例~\ref{exam:capname}。下面的选项（如
% \opt{contentsname}）主要用来重新定义与选项同名的宏（如 \cs{contentsname}）的
% 定义。
% 
% \begin{defaultcapconfig}
%
% \begin{function}{contentsname, \contentsname}
%   \begin{syntax}
%     contentsname = <名字>
%   \end{syntax}
% 设置目录标题名 \cs{contentsname}。中文默认为“\contentsname”。
% \end{function}
% 
% \begin{function}{listfigurename, \listfigurename}
%   \begin{syntax}
%     listfigurename = <名字>
%   \end{syntax}
% 设置插图目录标题名 \cs{listfigurename}。中文默认为“\listfigurename”。
% \end{function}
%
% \begin{function}{listtablename, \listtablename}
%   \begin{syntax}
%     listtablename = <名字>
%   \end{syntax}
% 设置表格目录标题名 \cs{listtablename}。中文默认为“\listtablename”。
% \end{function}
%
% \begin{function}{figurename, \figurename}
%   \begin{syntax}
%     figurename = <名字>
%   \end{syntax}
% 设置图片环境标题名 \cs{figurename}。中文默认为“\figurename”。
% \end{function}
%
% \begin{function}{tablename, \tablename}
%   \begin{syntax}
%     tablename = <名字>
%   \end{syntax}
% 设置表格环境标题名 \cs{tablename}。中文默认为“\tablename”。
% \end{function}
%
% \begin{function}{abstractname, \abstractname}
%   \begin{syntax}
%     abstractname = <名字>
%   \end{syntax}
% 设置摘要 \env{abstract} 环境标题名 \cs{abstractname}。中文默认
% 为“\abstractname”。注意 \cls{book} 类没有摘要，该选项无效。
% \end{function}
%
% \begin{function}{indexname, \indexname}
%   \begin{syntax}
%     indexname = <名字>
%   \end{syntax}
% 设置索引标题名 \cs{indexname}。中文默认为“\indexname”。
% \end{function}
%
% \begin{function}{appendixname}
%   \begin{syntax}
%     appendixname = <名字>
%   \end{syntax}
% 设置附录标题名 \cs{appendixname}。中文默认为“\appendixname”。
% \end{function}
%
% \begin{function}{bibname, \refname, \bibname}
%   \begin{syntax}
%     bibname = <名字>
%   \end{syntax}
% 设置参考文献标题名 \cs{refname}（对 \cls{article}）或 \cs{bibname}（对
% \cls{report} 和 \cls{book}）。中文默认为“\refname”。
% \end{function}
%
% \end{defaultcapconfig}
%
% \subsubsection{章节标题格式定义}
% \label{subsubs:secstyle}
%
% \CTeX 宏包对 \LaTeX 的标准文档类（\cls{article}、\cls{report} 和
% \cls{book}）进行了扩充。当以 \opt{heading} 选项调用 \CTeX 宏包时
% （\ref{subsubs:options-heading}~节），则会启用章
% 节标题的格式设置功能。本节就来介绍有关章节标题的格式选项，所有选项使用
% \cs{ctexset} 命令设置。
%
% 章节标题的格式选项是分层设置的。顶层的选项是章节标题名称，次一级的选项是章节
% 标题的格式。章节标题名包括 |part|, |chapter|, |section|, |subsection|,
% |subsubsecton|, |paragraph|, |subparagraph|；而可用的格式包括 \opt{name},
% \opt{number}, \opt{format}, \opt{nameformat}, \opt{numberformat},
% \opt{aftername}, \opt{titleformat}, \opt{beforeskip}, \opt{afterskip},
% \opt{indent}, \opt{pagestyle} 等。但注意，对 \cls{article} 及其衍生的
% \cls{ctexart} 等文档类，没有 |chapter| 级别的标题。
%
% 多级选项之间用斜线分开，例如，\opt{part/name} 选项设置 \cs{part} 标题的在数
% 字前后的名称，而 \opt{section/number} 选项设置 \cs{section} 标题的数字类型。
%
% \begin{function}{part/name, chapter/name, section/name, subsection/name,
%   subsubsection/name, paragraph/name, subparagraph/name}
%   \begin{syntax}
%     name = \{<前名字>,<后名字>\} \\
%     name = \Arg{前名字}
%   \end{syntax}
%   设置章节的名字。名字可以分为前后两部分，即章节编号前后的词语，两个词之间用
%   一个半角逗号分开；也可以只有一部分，表示只有章节编号之前的名字。例如：
%   \begin{ctexexam}
%   \ctexset{
%     chapter/name = {第,章},
%     section/name = {\S},
%   }
%   \end{ctexexam}
%   会使得 \cs{chapter} 标题使用形如“第一章”的名字，而 \cs{section} 标题则使
%   用形如“\S1”的名字。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{llll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值 & 注 \\
% \midrule
% part & |{第,部分}| & |{\partname\space}| & 原 \cs{partname} 为 Part \\
% chapter & |{第,章}| & |{\chaptername\space}|
%   & 原 \cs{chaptername} 为 Chapter \\
% section & |{}| & |{}| & \\
% subsection & |{}| & |{}| & \\
% subsubsection & |{}| & |{}| & \\
% paragraph & |{}| & |{}| & \\
% subparagraph & |{}| & |{}| & \\
% \bottomrule
% \end{tabular}
% \caption{\opt{name} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/number, chapter/number, section/number, subsection/number,
%   subsubsection/number, paragraph/number, subparagraph/number}
%   \begin{syntax}
%     number = \Arg{数字输出命令}
%   \end{syntax}
%   设置章节编号的数字输出格式。\meta{数字输出命令} 通常是对应章节编号计数器的
%   输出命令，如 |\thesection| 或 |\chinese{chapter}| 之类。
%   \begin{ctexexam}
%   \ctexset{
%     section/number = \Roman{section}
%   }
%   \end{ctexexam}
%
%   \opt{number} 选项的定义同时将控制对章节计数器的交叉引用。在引用计数器时，
%   记录在 \LaTeX{} 辅助文件中的是 \opt{number} 选项的定义。
%
%   但是，\opt{number} 选项不会影响计数器本身的输出。即设置 |section/number|
%   不会影响 \cs{thesection} 的定义。（但该选项会影响 \cs{CTEXthesection} 的定
%   义，见后。）
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{llll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值
%   & 原 |\the|\meta{标题} 等价定义 \\
% \midrule
% part & |\chinese{part}| & |\thepart| & |\Roman{part}| \\
% chapter & |\chinese{chapter}| & |\thechapter| & |\arabic{chapter}| \\
% section & 同右 & |\thesection| & |\arabic{section}| \\
% subsection & 同右 & |\thesubsection| & |\thesection.\arabic{subsection}| \\
% subsubsection & 同右 & |\thesubsubsection|
%   & |\thesubsection.\arabic{subsubsection}| \\
% paragraph & 同右 & |\theparagraph|
%   & |\thesubsubsection.\arabic{paragraph}| \\
% subparagraph & 同右 & |\thesubparagraph|
%   & |\theparagraph.\arabic{subparagraph}| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{number} 选项的默认设置}
% \end{table}
%
% \begin{function}{\CTEXthepart, \CTEXthechapter, \CTEXthesection,
%   \CTEXthesubsection, \CTEXthesubsubsection, \CTEXtheparagraph,
%   \CTEXthesubparagraph}
%   以 |\CTEXthe| 开头的这组宏给出结合了 \opt{name} 与 \opt{number} 选项的章节
%   编号输出格式。例如在 \opt{cap} 选项下的默认章编号输出格式就是
%   \cs{CTEXthechapter}，形如“第一章”。
%
%   这组宏在 \CTeX 文档类中将代替 \cs{thechapter} 等宏的作用，在章节中引用本章
%   节的完整编号。例如用于帮助定义自定义的目录格式、页眉格式等。
% \end{function}
%
% 使用 \cs{ctexset} 设置多级选项时，可以在同一个上级选项下设置多个下级选项。例
% 如同时设置 |section| 一级标题的 \opt{name} 与 \opt{number} 选项：
% \begin{ctexexam}
%   \ctexset{
%     section = {
%       name = {第,节},
%       number = \chinese{section}
%     }
%   }
% \end{ctexexam}
%
%
% \begin{function}{part/format, chapter/format, section/format,
%   subsection/format, subsubsection/format, paragraph/format,
%   subparagraph/format,
%   .../format+}
%   \begin{syntax}
%     format = \Arg{格式命令}
%     format+= \Arg{格式命令}
%   \end{syntax}
%   \opt{format} 选项用于控制章节标题的全局格式，作用域为章节名字和随后的标题
%   内容。可以用于控制章节标题的对齐方式、整体字体字号等格式。
%
%   带加号的 \opt{format+} 选项则用于在已有格式之后追加新的格式命令。
%
%   例如，设置章格式为无衬线字体左对齐，为节格式增加无衬线字体设置：
%   \begin{ctexexam}
%   \ctexset{
%     chapter/format=\sffamily\raggedright,
%     section/format+=\sffamily
%   }
%   \end{ctexexam}
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{lll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值 \\
% \midrule
% part (article) & |\centering| & |\raggedright| \\
% part & |\centering| & |\centering| \\
% chapter & |\centering| & |\raggedright| \\
% section & |\Large\bfseries\centering| & |\Large\bfseries| \\
% subsection & 同右 & |\large\bfseries| \\
% subsubsection & 同右 & |\normalsize\bfseries| \\
% paragraph & 同右 & |\normalsize\bfseries| \\
% subparagraph & 同右 & |\normalsize\bfseries| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{format} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/nameformat, chapter/nameformat, section/nameformat,
%   subsection/nameformat, subsubsection/nameformat, paragraph/nameformat,
%   subparagraph/nameformat,
%   .../nameformat+}
%   \begin{syntax}
%     nameformat = \Arg{格式命令}
%     nameformat+= \Arg{格式命令}
%   \end{syntax}
%   \opt{nameformat} 用于控制章节名字的格式，作用域为章节名字，包括编号。它一
%   般用于章节名（包括编号）与章节标题的字体、字号等设置不一致的情形。参见
%   \opt{titleformat} 选项。
%
%   \opt{nameformat+} 用于在已有的章节名字格式后附加内容。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{lll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值 \\
% \midrule
% part (article) & 同右 & |\Large\bfseries| \\
% part & 同右 & |\huge\bfseries| \\
% chapter & 同右 & |\huge\bfseries| \\
% section & 同右 & |{}| \\
% subsection & 同右 & |{}| \\
% subsubsection & 同右 & |{}| \\
% paragraph & 同右 & |{}| \\
% subparagraph & 同右 & |{}| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{nameformat} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/numberformat, chapter/numberformat,
%   section/numberformat, subsection/numberformat, subsubsection/numberformat,
%   paragraph/numberformat, subparagraph/numberformat,
%   .../numberformat+}
%   \begin{syntax}
%     numberformat = \Arg{格式命令}
%     numberformat+= \Arg{格式命令}
%   \end{syntax}
%   \opt{numberformat} 选项用于控制章节编号的格式，作用域仅为编号数字本身。对
%   各级标题默认均为空，当你需要编号的格式和前后的章节名字不一样时可以使用。
%
%   \opt{numberformat+} 选项用于在原有编号格式后面附加格式命令。
%
%   例如，我们可以使用 \opt{numberformat} 特别强调章标题中的数字：
%   \begin{ctexexam}
%   \ctexset{
%     chapter/number = \arabic{chapter},
%     chapter/numberformat = \color{blue}\zihao{0}\itshape,
%   }
%   \end{ctexexam}
%   上面的代码在 |cap| 选项下可以做出类似这样的章标题效果：
%   \begin{center}
%   \huge\bfseries 第 \textit{\color{blue}\zihao{0}4} 章
%   \end{center}
% \end{function}
%
% \begin{function}{part/aftername, chapter/aftername, section/aftername,
%   subsection/aftername, subsubsection/aftername, paragraph/aftername,
%   subparagraph/aftername}
%   \begin{syntax}
%   aftername=\Arg{代码}
%   \end{syntax}
%   \opt{aftername} 选项的参数\meta{代码}将被插入到章节编号与其后的标题内容之
%   间，用于控制格式变换。常用于控制章节编号与标题内容之间的距离，或者控制标题
%   是否另起一行。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{lll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值 \\
% \midrule
% part (article) & |\quad| & |\par\nobreak| \\
% part & 同右 & |\par\vskip 20pt| \\
% chapter & |\quad| & |\par\vskip 20pt| \\
% section & 同右 & |\quad| \\
% subsection & 同右 & |\quad| \\
% subsubsection & 同右 & |\quad| \\
% paragraph & 同右 & |\quad| \\
% subparagraph & 同右 & |\quad| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{aftername} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/titleformat, chapter/titleformat, section/titleformat,
%   subsection/titleformat, subsubsection/titleformat, paragraph/titleformat,
%   subparagraph/titleformat,
%   .../titleformat+}
%   \begin{syntax}
%     titleformat = \Arg{格式命令}
%     titleformat+= \Arg{格式命令}
%   \end{syntax}
%   \opt{titleformat} 选项用于控制标题内容的格式，作用域为章节标题内容。
%
%   \opt{titleformat+} 选项用于在原有标题格式后面附加格式命令。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{lll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值 \\
% \midrule
% part (article) & |\Large\bfseries| & |\huge\bfseries| \\
% part & |\huge\bfseries| & |\Huge\bfseries| \\
% chapter & |\huge\bfseries| & |\Huge\bfseries| \\
% section & 同右 & |{}| \\
% subsection & 同右 & |{}| \\
% subsubsection & 同右 & |{}| \\
% paragraph & 同右 & |{}| \\
% subparagraph & 同右 & |{}| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{titleformat} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/beforeskip, chapter/beforeskip, section/beforeskip,
%   subsection/beforeskip, subsubsection/beforeskip, paragraph/beforeskip,
%   subparagraph/beforeskip}
%   \begin{syntax}
%   beforeskip = \Arg{弹性间距}
%   \end{syntax}
%   \opt{beforeskip} 选项用于设置章节标题前的垂直间距及章节标题后首段的缩进。
%
%   \meta{弹性间距} 的绝对值被用于设置标题间的垂直间距，而\meta{弹性间距}的正
%   负号用于设置标题后第一段的首行缩进。当参数是负值时，章节标题后的第一段按英
%   文文档的排版习惯，没有首行缩进；参数是正值时，则保留首行缩进。
%
%   使用 \opt{sub3section} 或 \opt{sub4section} 宏包选项（见
%   \ref{subsubs:options-heading}~节）后，\cs{paragraph} 与 \cs{subparagraph}
%   这两级标题会改为排在不同段，会影响 \opt{beforeskip} 选项的默认值。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{lll}
% \toprule
% 标题名 & |cap=true| 的默认值 & |cap=false| 的默认值 \\
% \midrule
% part (article) & |4ex| & |-4ex| \\
% part & 无效 & 无效 \\
% chapter & |50pt| & |-50pt| \\
% section & |3.5ex plus 1ex minus .2ex| & |-3.5ex plus -1ex minus -.2ex| \\
% subsection & |3.25ex plus 1ex minus .2ex| & |-3.25ex plus -1ex minus -.2ex| \\
% subsubsection & |3.25ex plus 1ex minus .2ex| & |-3.25ex plus -1ex minus -.2ex| \\
% paragraph & 同右 & |3.25ex plus 1ex minus .2ex| \\
% \qquad(sub3section) & |3.25ex plus 1ex minus .2ex| & |-3.25ex plus -1ex minus -.2ex| \\
% \qquad(sub4section) & 同上 & 同上 \\
% subparagraph & 同右 & |3.25ex plus 1ex minus .2ex| \\
% \qquad(sub4section) & |3.25ex plus 1ex minus .2ex| & |-3.25ex plus -1ex minus -.2ex| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{beforeskip} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/afterskip, chapter/afterskip, section/afterskip,
%   subsection/afterskip, subsubsection/afterskip, paragraph/afterskip,
%   subparagraph/afterskip}
%   \begin{syntax}
%   afterskip = \Arg{弹性间距}
%   \end{syntax}
%   \opt{afterskip} 选项控制章节标题与后面下方之间的距离。\meta{弹性间距}的正
%   负号确定标题与后面正文是否排在同一段。如果是正值则正文另起一段，\meta{弹性
%   间距}给出垂直间距；如果是负值则章节标题与正文第一段排在同一段，\meta{弹性
%   间距}的绝对值给出水平间距。
%
%   默认情况下，\cs{paragraph}、\cs{subparagraph} 两级标题是与后面正文排在同一
%   段的，\opt{afterskip} 选项取负数；但使用 \opt{sub3section} 或
%   \opt{sub4section} 宏包选项（见 \ref{subsubs:options-heading}~节）后，则这
%   两级标题会改为排在不同段。
%
%   \opt{afterskip} 选项的默认值，在 \opt{cap} 选项的不同取值下相同。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{ll}
% \toprule
% 标题名 & 默认值 \\
% \midrule
% part (article) & |3ex| \\
% part & 无效 \\
% chapter & |40pt| \\
% section & |2.3ex plus .2ex| \\
% subsection & |1.5ex plus .2ex| \\
% subsubsection & |1.5ex plus .2ex| \\
% paragraph & |-1em| \\
% \qquad(sub3section) & |1ex plus .2ex| \\
% \qquad(sub4section) & 同上 \\
% subparagraph & |-1em| \\
% \qquad(sub4section) & |1ex plus .2ex| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{afterskip} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/intdent, chapter/intdent, section/intdent,
%   subsection/intdent, subsubsection/intdent, paragraph/intdent,
%   subparagraph/intdent}
%   \begin{syntax}
%   indent = \Arg{缩进间距}
%   \end{syntax}
%   \opt{indent} 选项用于设置章节标题本身的缩进。
%
%   \opt{indent} 选项的默认值，在 \opt{cap} 选项的不同取值下相同。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{ll}
% \toprule
% 标题名 & 默认值 \\
% \midrule
% part (article) & |0pt| \\
% part & 无效 \\
% chapter & |0pt| \\
% section & |0pt| \\
% subsection & |0pt| \\
% subsubsection & |0pt| \\
% paragraph & |0pt| \\
% subparagraph & |\parindent| \\
% \qquad(sub3section) & |0pt| \\
% \qquad(sub4section) & |0pt| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{indent} 选项的默认设置}
% \end{table}
%
% \begin{function}{part/pagestyle, chapter/pagestyle}
%   \begin{syntax}
%   pagestyle = \Arg{页面格式}
%   \end{syntax}
%   设置 \cls{book}/\cls{ctexbook} 或 \cls{report}/\cls{ctexrep} 文档类
%   中，\cs{part} 与 \cs{chapter} 标题所在页的页面格式（page style）。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{ll}
% \toprule
% 标题名 & 默认值 \\
% \midrule
% part (article) & 无效 \\
% part & |plain| \\
% chapter & |plain| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{pagestyle} 选项的默认设置}
% \end{table}
%
%
% \begin{function}{appendix/name}
%   \begin{syntax}
%     name = \{<前名字>,<后名字>\} \\
%     name = \Arg{前名字}
%   \end{syntax}
%   设置附录章（对 \cls{book} 与 \cls{report}）或附录节（对 \cls{article}）的
%   名字。用法与普通章节 \opt{name} 选项的类似。
%
%   注意该选项与 \opt{appendixname} 选项（\ref{subsubs:capname}~节）在意义上有
%   些重叠，但意义不同。\opt{appendixname} 选项只用来重定义
%   \cs{appendixname}，而不管 \cs{appendixname} 如何使用；该选项则决定在章节标
%   题中输出的名字，可以调用 \cs{appendixname} 设置。
% \end{function}
%
% \begin{table}[htb]
% \small\centering
% \begin{tabular}{llllll}
% \toprule
% 文档类 & 影响命令 & |cap=true| 的默认值 & 实际定义
%   & |cap=false| 的默认值 & 实际定义 \\
% \midrule
% article & \cs{section} & |{}| & & |{}| & \\
% book, report & \cs{chapter} & |\appendixname| & |附录|
%   & |\appendixname| & |Appendix| \\
% \bottomrule
% \end{tabular}
% \caption{\opt{appendix/name} 选项的默认设置}
% \end{table}
%
% \begin{function}{appendix/number}
%   \begin{syntax}
%   \end{syntax}
% \end{function}
%
% ^^A FIXME
%
% \subsubsection{页眉汉化}
%
% ^^A FIXME
%
% \subsection{关于 \LuaLaTeX{} 下的中文支持方式}
%
% 在 \LuaLaTeX{} 下，\CTeX{} 宏包依赖 \pkg{luatexja} 宏包来完成中文支持。
% 该宏包是日本 \TeX{} 社区的北川弘典、前田一贵、八登崇之等人开发的，设计目的主要
% 是在 \LuaTeX{} 引擎下实现日本 p\TeX{} 引擎的（大部分）功能。它为了兼容 p\LaTeX
% 的使用习惯，对 \LaTeXe 的 \pkg{NFSS} 作了不少修改和扩充。这对于简体中文用户来说
% 不是必要的，因而 \CTeX{} 禁用了它在 \LaTeX{} 格式下的大部分设置，只保留了必要的
% 部分。同时修改了它的字体设置方式，使得相关命令与 \pkg{xeCJK} 宏包大致相同。
%
% \subsubsection{\LuaLaTeX{} 下替代字体的设置}
%
% \begin{function}{AlternateFont}
%   \begin{syntax}
%     \cs{setCJKfamilyfont} \Arg{family}
%     \  [
%     \    AlternateFont =
%     \      \{
%     \        \Arg{character range_1} \oarg{alternate font features_1} \Arg{alternate font name_1} ||
%     \        \Arg{character range_2} \oarg{alternate font features_2} \Arg{alternate font name_2} ||
%     \        ......
%     \      \} ,
%     \    <base font features>
%     \  ] \Arg{base font name}
%   \end{syntax}
%   在设置字体族 \meta{family} 的时候，同时设置该字体族在字符范围
%   \meta{character range_n} 内，对应字形的替代字体。
% \end{function}
%
% \begin{function}{CharRange}
%   \begin{syntax}
%     \cs{setCJKfamilyfont} \Arg{family}
%     \  [
%     \    CharRange = \Arg{character range} ,
%     \    <alternate font features>
%     \  ] \Arg{alternate font name}
%   \end{syntax}
%   只设置字体族 \meta{family} 在字符范围 \meta{character range} 内，对应字形的
%   替代字体。
% \end{function}
%
% 一个 \cs{setCJKfamilyfont} 里只能使用一次 \opt{CharRange} 或者
% \opt{AlternateFont}，但可以将它们分开重叠使用。例如下面的方式是有效的。
%
% \begin{ctexexam}
%   \setCJKmainfont[AlternateFont={...}{...}, ...]{...}
%   \setCJKmainfont[CharRange={"4E00->"67FF,-2}, ...]{...}
%   \setCJKmainfont[CharRange={"6800->"9FFF}, ...]{...}
% \end{ctexexam}
%
% \begin{function}{declarecharrange}
%   \begin{syntax}
%     \cs{ctexset}
%     \  \{
%     \    declarecharrange =
%     \      \{
%     \        \Arg{name_1} \Arg{character range_1} ,
%     \        \Arg{name_2} \Arg{character range_2} ,
%     \        ...
%     \      \}
%     \  \}
%   \end{syntax}
%   预先声明字符范围。声明字符范围 \meta{name} 之后，它的名字 \meta{name} 可以
%   用在 \opt{AlternateFont} 和 \opt{CharRange} 选项的 \meta{character range}
%   之中，表示对应的字符范围。
% \end{function}
%
% 在声明字符范围 \meta{name} 的同时，还为 \cs{setCJKmainfont} 等字体设置命令定义
% 了选项 \meta{name}，用于设置对应字符的替代字体：
% \begin{quote}\linespread{1}\small\ttfamily
%   \meta{name} = \oarg{alternate font features} \Arg{alternate font name}
% \end{quote}
% \meta{name} 选项可以与 \opt{AlternateFont} 共同使用，但不能与 \opt{CharRange}
% 一起使用。如果没有给 \meta{name} 设置值，则等价于设置 \opt{CharRange=\meta{name}}，
% 即只设置 \meta{name} 对应的字符范围的替代字体。
%
% \begin{function}{clearalternatefont,resetalternatefont}
%   \begin{syntax}
%     \cs{ctexset}
%     \  \{
%     \    clearalternatefont = \Arg{family_1, family_2, ...} ,
%     \    resetalternatefont = \Arg{family_1, family_2, ...} ,
%     \    clearalternatefont ,
%     \    resetalternatefont
%     \  \}
%   \end{syntax}
%   清除与重置 CJK 字体族 \meta{family} 的替换字体设置。如果没有给定值，则作用于
%   当前 CJK 字体族。清除与重置操作总是全局的。
% \end{function}
%
% \subsection{杂项}
%
% \begin{function}{\CTeX}
% 用于显示 \CTeX 的标志。
% \end{function}
%
% \section{对旧版本的兼容性}
%
% 这里介绍新版本 \CTeX 宏包相对 1.02d 版本（2014/06/09）的兼容性。
%
% \begin{function}{indent, noindent}
% \end{function}
%
% \begin{function}{\CTEXindent}
% \end{function}
%
% \begin{function}{\CTEXnoindent}
% \end{function}
%
% \begin{function}{\CTEXsetup}
% \end{function}
%
% \begin{function}{\CTEXoptions}
% \end{function}
%
% \begin{function}{captiondelimiter}
% \end{function}
%
%
% ^^A FIXME
%
% \section{开发人员}
%
% \begin{itemize}
% \item 吴凌云 (\email{aloft@ctex.org})
% \item 江疆 (\email{gzjjgod@gmail.com})
% \item 王越 (\email{yuleopen@gmail.com})
% \item 刘海洋 (\email{LeoLiu.PKU@gmail.com})
% \item 李延瑞 (\email{LiYanrui.m2@gmail.com})
% \item 陈之初 (\email{zhichu.chen@gmail.com})
% \item 李清 (\email{sobenlee@gmail.com})
% \item 黄晨成 (\email{liamhuang0205@gmail.com})
% \end{itemize}
%
%
% \end{documentation}
%
%
% \StopEventually{}
%
%
%\begin{implementation}
%
% \section{代码实现}
%
%    \begin{macrocode}
%<@@=ctex>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*ctexcap>
\PassOptionsToPackage { heading = true } { ctexcap }
\RequirePackageWithOptions { ctex }
%</ctexcap>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*class|style|ctexsize>
\RequirePackage { xparse , l3keys2e }
%</class|style|ctexsize>
%    \end{macrocode}
%
% 检查 \pkg{expl3} 和 \pkg{l3keys2e} 的版本。
%    \begin{macrocode}
%<*class>
\msg_new:nnnn { ctex } { l3-too-old }
  { Support~package~`#1'~too~old. }
  {
    Please~update~an~up~to~date~version~of~the~bundles\\\\
    `l3kernel'~and~`l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
\@ifpackagelater { expl3 } { 2014/07/20 } { }
  { \msg_error:nnn { ctex } { l3-too-old } { expl3 } }
\@ifpackagelater { l3keys2e } { 2014/05/05 } { }
  { \msg_error:nnn { ctex } { l3-too-old } { l3keys2e } }
%</class>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*class|style>
\RequirePackage { etoolbox , ifpdf , fix-cm , everysel }
%    \end{macrocode}
%
% \subsection{内部函数与变量}
%
% \begin{variable}[internal]
% {\l_@@_tmp_tl,\g_@@_tmp_bool,\l_@@_tmp_int,\l_@@_tmp_dim,\l_@@_tmp_box}
%    \begin{macrocode}
\tl_new:N \l_@@_tmp_tl
\bool_new:N \g_@@_tmp_bool
\int_new:N \l_@@_tmp_int
\dim_new:N \l_@@_tmp_dim
\box_new:N \l_@@_tmp_box
\seq_new:N \l_@@_tmp_seq
%    \end{macrocode}
% \end{variable}
%
% 对旧版本的宏包给出错误信息。
%    \begin{macrocode}
\msg_new:nnnn { ctex } { package-too-old }
  { Support~package~`#1'~too~old. }
  {
    Please~update~an~up~to~date~version~of~the~package~`#1'\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_lua_now_x:n}
% 最新的 \pkg{expl3} 去掉了 \pkg{l3luatex} 模块，因而 \cs{lua_now_x:n} 不再有定义。
%    \begin{macrocode}
\cs_new_eq:NN \ctex_lua_now_x:n \luatex_directlua:D
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_if_pdfmode:TF}
% \cs{ifpdf} 的简单 wrapper。
%    \begin{macrocode}
\ifpdf
  \cs_new_eq:NN \ctex_if_pdfmode:TF \use_i:nn
\else:
  \cs_new_eq:NN \ctex_if_pdfmode:TF \use_ii:nn
\fi:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_file_input:n}
% 使用 \cs{@pushfilename} 和 \cs{@popfilename} 是为了让文件可以不受当前
% \LTXIII{} 语法环境的影响。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_file_input:n #1
  { \@pushfilename \file_input:n {#1} \@popfilename }
\@onlypreamble \ctex_file_input:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_parse_name:NN}
% 用 \cs{DeclareRobustCommand} 定义的宏或者由 \cs{newcommand} 或 \cs{newrobustcmd}
% 定义的带一个可选参数的宏第一次展开的结果都不是其实际定义，实际定义被保存在另外的
% 宏中。由这些命令定义的宏的第一次展开结果可以有下面的形式（细节可查阅 \pkg{xpatch}
% 的文档）：
% \begin{verbatim}[numbers=left,gobble=4]
%   \protect␣\xaa␣␣                    % \DeclareRobustCommand\xaa[1]{...}
%   \protect␣\xab␣␣                    % \DeclareRobustCommand\xab[1][]{...}
%   \@protected@testopt␣\xac␣\\xac␣{}  % \newcommand\xac[1][]{...}
%   \@testopt␣\\xad␣{}                 % \newrobustcmd\xad[1][]{...}
%   \x@protect␣\1\protect␣\1␣␣         % \DeclareRobustCommand\1[1]{...}
%   \x@protect␣\2\protect␣\2␣␣         % \DeclareRobustCommand\2[1][]{...}
%   \@protected@testopt␣\3\\3␣{}       % \newcommand\3[1][]{...}
%   \@testopt␣\\4␣{}                   % \newrobustcmd\4[1][]{...}
% \end{verbatim}
% \pkg{etoolbox} 的 \cs{patchcmd} 的主要原理是先对宏的 \cs{meaning} 作字符串
% 替换，然后再用 \cs{scantokens} 来重建它。我们希望对宏的实际定义打补丁，为此需要
% 先得到对应的名字。\pkg{letltxmacro}、\pkg{show2e} 和 \pkg{xpatch} 宏包中都有
% 类似的工作。我们不想依赖 \pkg{xpatch}，主要是因为它与同作者的 \pkg{regexpatch}
% 宏包共用了主要函数的名字，从而将导致用户不能使用 \pkg{regexpatch}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_parse_name:NN #1#2
  { \ctex_parse_name:NNx #1#2 { \cs_to_str:N #2 } }
\group_begin:
\char_set_lccode:nn { `\< } { `\{ }
\char_set_lccode:nn { `\/ } { `\\ }
\char_set_lccode:nn { `\A } { `\t }
\tl_map_function:nN { \A \E \S \O \P } \char_set_catcode_other:N
\tex_lowercase:D
  {
    \group_end:
    \cs_new_protected:Npn \ctex_parse_name:NNn #1#2#3
      {
        \bool_if:nTF { \cs_if_exist_p:c { #3 ~ } || \cs_if_exist_p:c { /#3 } }
          {
            \group_begin:
            \use:x
              {
                \@@_parse_name:nNNNnN { \token_get_replacement_spec:N #2 }
                  \exp_not:N #2 \exp_not:c { #3 ~ } \exp_not:c { /#3 } {#3}
              } #1
          }
          { #1#2 }
      }
    \cs_new_protected:Npn \@@_parse_name:nNNNnN #1#2#3#4#5#6
      {
        \group_end:
        \exp_args:Nc #6
          {
            \str_case:nnTF {#1}
              {
                { \protect #3 } { }
                { \x@protect #2 \protect #3 } { }
              }
              {
                \str_if_eq_x:nnTF { \exp_not:n { /@protected@ #3 /#3 } }
                  {
                    \exp_last_unbraced:Nf \@@_parse_name:w
                    \token_get_replacement_spec:N #3 AESAOPA ~ < \q_stop
                  }
                  { /#5 ~ } { #5 ~ }
              }
              {
                \str_case:onTF { \@@_parse_name:w #1 AESAOPA ~ < \q_stop }
                  {
                    { /@protected@ #2 #4 } { }
                    { /@ #4 } { }
                  }
                  { /#5 } {#5}
              }
          }
      }
    \cs_new:Npn \@@_parse_name:w #1 AESAOPA ~ #2 < #3 \q_stop { #1#2 }
  }
\cs_generate_variant:Nn \ctex_parse_name:NNn { NNx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\ctex_patch_cmd:NnnTF,\ctex_preto_cmd:NnTF,\ctex_appto_cmd:NnTF}
% 在打补丁前先解析实际名字。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_patch_cmd:NnnTF { \ctex_parse_name:NN \patchcmd }
\cs_new_protected:Npn \ctex_preto_cmd:NnTF  { \ctex_parse_name:NN \pretocmd }
\cs_new_protected:Npn \ctex_appto_cmd:NnTF  { \ctex_parse_name:NN \apptocmd }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_patch_cmd:Nnn}
% 参数记号 |#| 作为宏的参数被读入时，总是会双写，会影响随后的字符串替换。需要先
% 将它转换为普通符号。并且在补丁的时候关闭 \LTXIII{} 语法。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_patch_cmd:Nnn
  {
    \group_begin:
    \char_set_catcode_other:N \#
    \@@_patch_cmd:Nnn
  }
\cs_new_protected:Npn \@@_patch_cmd:Nnn #1#2#3
  {
    \group_end:
    \group_begin:
    \ExplSyntaxOff
    \ctex_patch_cmd:NnnTF #1 {#2} {#3}
      {
        \cs_gset_eq:NN \@@_tmp:w #1
        \group_end:
        \cs_set_eq:NN #1 \@@_tmp:w
        \cs_undefine:N \@@_tmp:w
      }
      { \group_end: \ctex_patch_failure:N #1 }
  }
\cs_new_protected:Npn \ctex_patch_failure:N #1
  { \msg_warning:nnx { ctex } { patch-failure } { \token_to_str:N #1 } }
\msg_new:nnn { ctex } { patch-failure }
  {
    Patching~command~`#1'~failed.\\
    ctex~may~not~work~as~expected.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_default_pt:n}
% 最新版本的 \pkg{expl3} 已经不允许 \cs{dim_to_pt:n} 的参数带额外的单位。然而我们
% 需要这个特性实现可展的 \cs{@defaultunits}。
%    \begin{macrocode}
\cs_new:Npn \ctex_default_pt:n #1
  {
    \exp_after:wN \@@_default_pt:w
      \dim_use:N \etex_dimexpr:D #1 pt \scan_stop: \q_stop
  }
\group_begin:
  \char_set_catcode_other:N \P
  \char_set_catcode_other:N \T
\tex_lowercase:D
  {
    \group_end:
    \cs_new:Npn \@@_default_pt:w #1 PT #2 \q_stop { #1 PT }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}[internal]{\l_@@_encoding_tl}
% (pdf)\LaTeX{} 初始化编码为 GBK，其它则是 UTF8。
%    \begin{macrocode}
\tl_new:N \l_@@_encoding_tl
\tl_set:Nx \l_@@_encoding_tl
  { \pdftex_if_engine:TF { GBK } { UTF8 } }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}[internal]{\g_@@_section_depth_flag}
% 若大于 |3|，则 \cs{paragraph} 和 \cs{subparagraph} 标题单独占一行；若为 |3|，则
% \cs{paragraph} 单独占一行。
%    \begin{macrocode}
\cs_new_eq:NN \g_@@_section_depth_flag \c_two
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}[internal]{\g_@@_zhmCJK_bool}
% 是否使用 \pkg{zhmCJK} 宏包。
%    \begin{macrocode}
\bool_new:N \g_@@_zhmCJK_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[internal]{\ctex_zhmap_case:nnn}
% 参数 |#1| 是 \pkg{zhmCJK} 的内容，|#2| 是 \pkg{zhmetrics}。
%    \begin{macrocode}
\cs_new_eq:NN \ctex_zhmap_case:nnn \use_ii:nnn
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_at_end:n}
% 区分 \cs{AtEndOfClass} 和 \cs{AtEndOfPackage}，虽然它们的意思都是一样的。
%    \begin{macrocode}
%<class>\cs_new_protected_nopar:Npn \ctex_at_end:n { \AtEndOfClass }
%<style>\cs_new_protected_nopar:Npn \ctex_at_end:n { \AtEndOfPackage }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}[internal]{\g_@@_std_options_clist}
% 保存传递给标准文档类的选项。
%    \begin{macrocode}
%<*class>
\clist_new:N \g_@@_std_options_clist
%</class>
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%</class|style>
%<*class|style|ctexsize>
%    \end{macrocode}
%
% \begin{variable}[internal]{\g_@@_font_size_flag}
% |0| 表示修改默认字体大小为五号，|1| 为小四号，其它值则不作修改。
%    \begin{macrocode}
\cs_new_eq:NN \g_@@_font_size_flag \c_zero
%    \end{macrocode}
% \end{variable}
%
% 对无效选项给出警告。
%    \begin{macrocode}
\msg_new:nnn { ctex } { invalid-option }
  { Option~`\l_keys_key_tl'~is~invalid~in~current~mode. }
\msg_new:nnn { ctex } { invalid-value }
  { Value~`#1'~is~invalid~for~the~key~`\l_keys_key_tl'. }
%    \end{macrocode}
%
% \subsection{宏包选项}
%
%   \begin{macrocode}
\keys_define:nn { ctex / option }
  {
%    \end{macrocode}
%
% \begin{macro}{c5size,cs4size}
%    \begin{macrocode}
    c5size  .code:n = { \cs_gset_eq:NN \g_@@_font_size_flag \c_zero } ,
    cs4size .code:n = { \cs_gset_eq:NN \g_@@_font_size_flag \c_one } ,
    c5size  .value_forbidden: ,
    cs4size .value_forbidden: ,
%<ctexsize>  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</class|style|ctexsize>
%<*class|style>
%    \end{macrocode}
%
% \changes{v2.0}{2014/04/23}{新增 \opt{linespread} 选项。}
%
% \begin{macro}{linespread}
% 行距初始值为 $1.3\times 1.2=2.56$ 倍字体大小。
%    \begin{macrocode}
    linespread  .fp_set:N = \l_@@_line_spread_fp ,
    linespread .initial:n = { 1.3 } ,
    linespread .value_required: ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/13}{新增 \opt{autoindent} 选项。}
%
% \begin{macro}{autoindent}
% 自动调整段落的首行缩进功能。
%    \begin{macrocode}
    autoindent .bool_set:N = \l_@@_autoindent_bool ,
    autoindent  .initial:n = { true } ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{indent}
% 仅为兼容性保留，不建议使用。
%    \begin{macrocode}
    indent .bool_set:N = \l_@@_indent_bool ,
    noindent   .meta:n = { indent = false } ,
    noindent   .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{GBK,UTF8}
%   \begin{macrocode}
    GBK  .code:n = { \tl_set:Nn \l_@@_encoding_tl { GBK } } ,
    UTF8 .code:n = { \tl_set:Nn \l_@@_encoding_tl { UTF8 } } ,
    GBK  .value_forbidden: ,
    UTF8 .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/08}{新增 \opt{fontset} 选项。}
%
% \begin{macro}{fontset}
% 初始值为空。若用户未指定，则根据操作系统载入对应字体配置，可以区分 Windows、
% Mac~OS~X 和其它。
%   \begin{macrocode}
    fontset  .tl_gset:N = \g_@@_fontset_tl ,
    nofonts     .meta:n = { fontset = none } ,
    adobefonts  .meta:n = { fontset = adobe } ,
    winfonts    .meta:n = { fontset = windows } ,
    fontset     .value_required: ,
    nofonts     .value_forbidden: ,
    winfonts    .value_forbidden: ,
    adobefonts  .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/08}{新增 \opt{zhmCJK} 支持选项。}
%
% \begin{macro}{zhmap}
%   \begin{macrocode}
    zhmap .choice: ,
    zhmap .default:n = { true } ,
    zhmap / zhmCJK .code:n =
      {
        \bool_gset_true:N \g_@@_zhmCJK_bool
        \cs_gset_eq:NN \ctex_zhmap_case:nnn \use_i:nnn
      } ,
    zhmap / true   .code:n =
      {
        \bool_gset_false:N \g_@@_zhmCJK_bool
        \cs_gset_eq:NN \ctex_zhmap_case:nnn \use_ii:nnn
      } ,
    zhmap / false  .code:n =
      {
        \bool_gset_false:N \g_@@_zhmCJK_bool
        \cs_gset_eq:NN \ctex_zhmap_case:nnn \use_iii:nnn
      } ,
    nozhmap   .meta:n = { zhmap = false } ,
    nozhmap   .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/04/11}{\opt{punct} 选项可以设置标点格式。}
%
% \begin{macro}{punct}
% 设置标点符号输出格式。
%   \begin{macrocode}
    punct   .tl_set:N = \l_@@_punct_tl ,
    punct  .default:n = { quanjiao } ,
    punct  .initial:n = { quanjiao } ,
    nopunct   .meta:n = { punct = plain } ,
    nopunct   .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{space}
%   \begin{macrocode}
    space .choices:nn =
      { true , auto , false }
      {
        \exp_args:Nx \ctex_at_end:n
          { \keys_set:nn { ctex } { space = \l_keys_choice_tl } }
      } ,
    space  .default:n = { true } ,
    nospace   .meta:n = { space = false } ,
    nospace   .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/08}{\pkg{ctex.sty} 新增 \opt{heading} 选项。}
%
% \begin{macro}{heading}
%   \begin{macrocode}
    heading .bool_set:N = \l_@@_heading_bool ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{cap}
%    \begin{macrocode}
    cap .bool_set:N = \l_@@_caption_bool ,
    cap  .initial:n = { true } ,
    nocap   .meta:n = { cap = false } ,
    nocap   .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{sub3section,sub4section}
% \begin{macrocode}
    sub3section .code:n =
      { \cs_gset_eq:NN \g_@@_section_depth_flag \c_three } ,
    sub4section .code:n =
      { \cs_gset_eq:NN \g_@@_section_depth_flag \c_four } ,
    sub3section .value_forbidden: ,
    sub4section .value_forbidden: ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{fntef,fancyhdr,hyperref}
%   \begin{macrocode}
    fntef    .bool_set:N = \l_@@_fntef_bool ,
    fancyhdr .bool_set:N = \l_@@_fancyhdr_bool ,
    hyperref .bool_set:N = \l_@@_hyperref_bool
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</class|style>
%<*class|style|ctexsize>
%    \end{macrocode}
%
% \begin{macro}{10pt,11pt,12pt}
% 使 \pkg{ctex} 和 \pkg{ctexsize} 可以接受文档类的全局选项，不修改默认字体大小。
% 在文档类下还将参数传给标准文档类。
%    \begin{macrocode}
\clist_map_inline:nn { 10pt , 11pt , 12pt }
  {
    \keys_define:nn { ctex / option }
      {
        #1 .code:n =
%<*!class>
          { \cs_gset_eq:NN \g_@@_font_size_flag \c_minus_one } ,
%</!class>
%<*class>
          {
            \cs_gset_eq:NN \g_@@_font_size_flag \c_minus_one
            \clist_gput_right:Nn \g_@@_std_options_clist {#1}
          } ,
%</class>
        #1 .value_forbidden:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 将未知选项传给标准文档类。
%    \begin{macrocode}
%<*class>
\keys_define:nn { ctex / option }
  {
    unknown .code:n =
      { \clist_gput_right:No \g_@@_std_options_clist { \CurrentOption } }
  }
%</class>
%    \end{macrocode}
%
%    \begin{macrocode}
%<!ctexsize>\ctex_file_input:n { ctexopts.cfg }
%    \end{macrocode}
%
%    \begin{macrocode}
\ProcessKeysOptions { ctex / option }
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|style|ctexsize>
%<*class|style>
%    \end{macrocode}
%
% 五号字使用标准文档类的 |10pt| 字体大小设置，小四号字则使用 |12pt|。
%    \begin{macrocode}
%<*class>
\if_case:w \g_@@_font_size_flag
  \clist_gput_right:Nn \g_@@_std_options_clist { 10pt }
\or:
  \clist_gput_right:Nn \g_@@_std_options_clist { 12pt }
\fi:
%    \end{macrocode}
%
% 使用 \cs{PassOptionsToClass} 是为了预防可能存在的选项冲突。
%    \begin{macrocode}
%<*article>
\PassOptionsToClass { \g_@@_std_options_clist } { article }
\LoadClass { article }
%</article>
%<*book>
\PassOptionsToClass { \g_@@_std_options_clist } { book }
\LoadClass { book }
%</book>
%<*report>
\PassOptionsToClass { \g_@@_std_options_clist } { report }
\LoadClass { report }
%</report>
%</class>
%    \end{macrocode}
%
%    \begin{macrocode}
\tl_set_eq:Nc \l_@@_tmp_tl { ver@ \@currname . \@currext }
%<*class>
\cs_new_eq:cN { ver@ctex.     \@pkgextension } \l_@@_tmp_tl
\cs_new_eq:cN { ver@ctexcap.  \@pkgextension } \l_@@_tmp_tl
\cs_new_eq:cN { ver@ctexsize. \@pkgextension } \l_@@_tmp_tl
%</class>
%<*style>
\msg_new:nnnn { ctex } { ctexsize-loaded }
  { Package~`ctexsize'~can~not~be~loaded~before~`ctex'. }
  {
    `ctexsize'~is~actually~a~part~of~`ctex'.\\
    It~is~not~necessary~to~load~it~separately.
  }
\@ifpackageloaded { ctexsize }
  { \msg_error:nn { ctex } { ctexsize-loaded } }
  { \cs_new_eq:cN { ver@ctexsize. \@pkgextension } \l_@@_tmp_tl }
%</style>
%    \end{macrocode}
%
% \subsection{用户设置接口}
%
% \changes{v2.0}{2014/03/18}{新增统一设置接口 \cs{ctexset}。}
%
% \begin{macro}{\ctexset}
%    \begin{macrocode}
\NewDocumentCommand \ctexset { +m }
  { \keys_set:nn { ctex } {#1} }
%    \end{macrocode}
% \end{macro}
%
% 过时命令。
% \begin{macro}{\CTEXsetup,\CTEXoptions}
%    \begin{macrocode}
\NewDocumentCommand \CTEXsetup { +o > { \TrimSpaces } m }
  { \IfNoValueF {#1} { \keys_set:nn { ctex / #2 } {#1} } }
\NewDocumentCommand \CTEXoptions { +o }
  { \IfNoValueF {#1} { \keys_set:nn { ctex } {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{引擎支持}
%
% \begin{macro}[internal]{\hypersetup}
%    \begin{macrocode}
\bool_if:NT \l_@@_hyperref_bool
  {
    \cs_if_exist:NF \hypersetup
      {
        \cs_new_protected:Npn \hypersetup #1
          { \PassOptionsToPackage {#1} { hyperref } }
      }
    \hypersetup { colorlinks = true }
    \AtEndPreamble { \RequirePackage { hyperref } }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\pdftex_if_engine:TF
  {
    \tl_set:Nx \l_@@_encoding_tl { \l_@@_encoding_tl }
    \ctex_file_input:n { ctex-engine-pdftex.def }
  }
  {
    \tl_set:Nn \l_@@_encoding_tl { UTF8 }
    \xetex_if_engine:TF
      { \ctex_file_input:n { ctex-engine-xetex.def } }
      { \ctex_file_input:n { ctex-engine-luatex.def } }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|style>
%<*pdftex>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-pdftex.def}}
%
% 首先检查选项，决定是否载入 \pkg{zhmCJK} 宏包。
%    \begin{macrocode}
\if_bool:N \g_@@_zhmCJK_bool
  \PassOptionsToPackage { encoding = \l_@@_encoding_tl } { zhmCJK }
  \RequirePackage { zhmCJK }
%    \end{macrocode}
% 不载入 \pkg{zhmCJK} 宏包时直接调用 \pkg{CJK} 及相关宏包。
%    \begin{macrocode}
\else:
  \str_if_eq:onTF { \l_@@_encoding_tl } { GBK }
    { \RequirePackage { CJK } }
    { \RequirePackage { CJKutf8 } }
  \RequirePackage { CJKpunct , CJKspace }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_load_zhmap:nnnn}
% 载入 \pkg{zhmetrics} 的字体映射文件，同时设置 \tn{CJKrmdefault} 等。
%    \begin{macrocode}
  \cs_new_protected_nopar:Npn \ctex_load_zhmap:nnnn #1#2#3#4
    {
      \tl_set:Nn \CJKrmdefault {#1}
      \tl_set:Nn \CJKsfdefault {#2}
      \tl_set:Nn \CJKttdefault {#3}
      \AtBeginDvi { \file_input:n {#4} }
      \AtBeginDocument
        { \cs_if_exist_use:NT \AtBeginShipoutFirst { { \file_input:n {#4} } } }
    }
  \@onlypreamble \ctex_load_zhmap:n
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
  \tl_if_exist:NF \CJKfamilydefault
    { \tl_const:Nn \CJKfamilydefault { \CJKrmdefault } }
  \tl_if_exist:NF \CJKrmdefault { \tl_new:N \CJKrmdefault }
  \tl_if_exist:NF \CJKsfdefault { \tl_new:N \CJKsfdefault }
  \tl_if_exist:NF \CJKttdefault { \tl_new:N \CJKttdefault }
  \ctex_preto_cmd:NnTF \rmfamily { \CJKfamily { \CJKrmdefault } } { }
    { \ctex_patch_failure:N \rmfamily }
  \ctex_preto_cmd:NnTF \sffamily { \CJKfamily { \CJKsfdefault } } { }
    { \ctex_patch_failure:N \sffamily }
  \ctex_preto_cmd:NnTF \ttfamily { \CJKfamily { \CJKttdefault } } { }
    { \ctex_patch_failure:N \ttfamily }
  \ctex_preto_cmd:NnTF \normalfont { \CJKfamily { \CJKfamilydefault } }
    { \cs_set_eq:NN \reset@font \normalfont }
    { \ctex_patch_failure:N \normalfont }
%    \end{macrocode}
%
% \cs{CJK@makeActive} 应该先于 \file{ctexcap-gbk.cfg} 等文件的载入，将汉字的
% 首字节设置为活动字符。使用 \pkg{zhmCJK} 时，此功能已经被启用。
%    \begin{macrocode}
  \CJK@makeActive
%    \end{macrocode}
%
% \pkg{zhmCJK} 判断结束。
%    \begin{macrocode}
\fi:
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_CJK_input:n,\CJK@input}
% \pkg{breqn} 包可能会在正文中将 |^| 的 \cs{catcode} 改为 $12$ 或 $13$，这将
% 破坏 \pkg{CJK} 对汉字的首字节的定义（\cs{CJK@loadBinding} 和
% \cs{CJK@loadEncoding}）。因此需要确保载入 \file{.enc} 和 \file{.bdg} 文件时，
% |^| 的 \cs{catcode} 为 $7$。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_CJK_input:n #1
  {
    \use:x
      {
        \char_set_catcode_other:n            { 60 } % <
        \char_set_catcode_letter:n           { 64 } % @
        \char_set_catcode_math_superscript:n { 94 } % ^
        \int_set_eq:NN \tex_endlinechar:D \c_minus_one
        \file_input:n {#1}
        \int_set:Nn \tex_endlinechar:D { \int_use:N \tex_endlinechar:D }
        \char_set_catcode:nn { 60 } { \char_value_catcode:n { 60 } }
        \char_set_catcode:nn { 64 } { \char_value_catcode:n { 64 } }
        \char_set_catcode:nn { 94 } { \char_value_catcode:n { 94 } }
      }
  }
\cs_set_eq:NN \CJK@input \ctex_CJK_input:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_plane_to_utfxvibe:Nn,\CJK@surr}
% \changes{v2.0}{2014/04/08}{解决与 \cs{nouppercase} 的冲突。}
% \pkg{fancyhdr} 宏包的 \cs{nouppercase} 会将 \cs{uppercase} 定义为 \cs{relax}，而
% \cs{CJK@surr} 需要用它将 \cs{CJK@plane} 转化成大写字母，这就造成了冲突^^A
% \footnote{\url{https://code.google.com/p/ctex-kit/issues/detail?id=147}}。
% 我们在这里给出 \cs{CJK@surr} 的一个不依赖 \cs{uppercase} 的实现。
%    \begin{macrocode}
\if_cs_exist:N \CJK@surr
  \cs_new_protected_nopar:Npn \ctex_plane_to_utfxvibe:Nn #1#2
    {
      \tl_set:Nx \l_@@_tmp_tl {#2}
      \int_set:Nn \l_@@_tmp_int
        { \exp_args:No \int_from_hex:n { \l_@@_tmp_tl } }
      \int_compare:nNnTF \l_@@_tmp_int < \c_two_hundred_fifty_six
        { \tl_gset:Nx #1 { \int_to_Hex:n { \l_@@_tmp_int } } }
        {
          \int_sub:Nn \l_@@_tmp_int { \c_two_hundred_fifty_six }
          \tl_gset:Nx #1
            {
              \int_to_Hex:n
                { \int_div_truncate:nn { \l_@@_tmp_int } { \c_four } + "D800 }
              \int_to_Hex:n
                { \int_mod:nn { \l_@@_tmp_int } { \c_four } + "DC }
            }
        }
    }
  \cs_set_eq:NN \CJK@surr \ctex_plane_to_utfxvibe:Nn
\fi:
%    \end{macrocode}
% \end{macro}
%
% \pkg{CJKpunct} 宏包会在 \cs{AtBeginDocument} 的里设置标点格式为 \opt{quanjiao}。
%    \begin{macrocode}
\str_if_eq_x:nnF { \l_@@_punct_tl } { quanjiao }
  { \AtBeginDocument { \punctstyle { \l_@@_punct_tl } } }
%    \end{macrocode}
%
% \tn{CJK@envStart} 的定义是
% \begin{verbatim}
%   \def\CJK@envStart#1#2#3{
%     \CJK@upperReset
%     \ifCJK@lowercase@
%       \CJK@lowerReset
%     \fi%
%     \CJK@makeActive%
%     \CJK@global\let\CJK@selectFamily \CJK@selFam
%     \CJK@global\let\CJK@selectEnc \CJK@selEnc%
%     \def\CJK@@@enc{#2}
%     \ifx\CJK@@@enc \@empty
%       \PackageInfo{CJK}{
%         no encoding parameter given,\MessageBreak
%         waiting for \protect\CJKenc\space commands}
%     \else
%       \CJKenc{#2}
%     \fi
%     \CJKfontenc{#2}{#1}
%     \CJKfamily{#3}
%     \def\CJK@series{\f@series}
%     \def\CJK@shape{\f@shape}%
%     \csname CJKhook\endcsname}
% \end{verbatim}
% \tn{CJK@upperReset} 可能会有一定风险，因此我们直到导言区末尾才使用
% \tn{CJK@envStart}。这样可以避免将 \env{CJK} 环境内置入 \env{document} 环境的
% 最里层，最后也就不需要 \tn{clearpage}。
%    \begin{macrocode}
\exp_args:Nx \AtEndPreamble
  {
    \exp_not:N \CJK@envStart
      { } { \l_@@_encoding_tl } { \exp_not:N \CJKfamilydefault }
    \exp_not:N \CJKtilde
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\CJK@ignorespaces,\ctex_auto_ignorespaces:}
% 默认忽略汉字之间的空格。并关闭名字空间，保存 |\CJK@@ignorespaces| 的定义，方便使用。
%    \begin{macrocode}
%<@@=>
\cs_set_eq:NN \CJK@ignorespaces \CJK@@ignorespaces
\cs_new_eq:NN \ctex_auto_ignorespaces: \CJK@@ignorespaces
%    \end{macrocode}
% 恢复名字空间，要把它放在一个 \env{macrocode} 环境中，\cls{l3doc} 才能正确工作。
%    \begin{macrocode}
%<@@=ctex>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_punct_set:n}
% 设置 CJK 族对应到实际的字体。|#1| 是 \opt{fontset} 的名字。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_punct_set:n #1
  {
    \clist_map_inline:Nn \c_@@_punct_family_clist
      {
        \cs_if_free:cF { CJKpunct@ #1 ##1 @spaces }
          {
            \cs_set_eq:cc
              { CJKpunct@ ##1 @spaces }
              { CJKpunct@ #1 ##1 @spaces }
          }
      }
  }
\clist_const:Nn \c_@@_punct_family_clist
  {
    zhsong , zhhei , zhfs , zhkai , zhli , zhyou ,
    zhsongb , zhheil , zhheib , zhyoub , zhyahei , zhyaheib
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_punct_map_family:nn}
% CJK 族 |#1| 使用族 |#2| 的边界信息。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_punct_map_family:nn #1#2
  {
    \cs_if_free:cF { CJKpunct@ #2 @spaces }
      { \cs_set_eq:cc { CJKpunct@ #1 @spaces } { CJKpunct@ #2 @spaces } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_punct_map_bfseries:nn}
% CJK 族 |#1| 的 \tn{bfseries} 使用族 |#2| 的边界信息。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_punct_map_bfseries:nn #1#2
  {
    \clist_map_inline:nn {#1}
      {
        \ctex_punct_map_series:nnn { ##1 } { b } {#2}
        \ctex_punct_map_series:nnn { ##1 } { bx } {#2}
      }
  }
\cs_new_protected_nopar:Npn \ctex_punct_map_series:nnn #1#2#3
  {
    \CJKpunctmapfamily { C19 } {#1} {#2} { m }  {#3}
    \CJKpunctmapfamily { C19 } {#1} {#2} { it } {#3}
    \CJKpunctmapfamily { C19 } {#1} {#2} { sl } {#3}
    \CJKpunctmapfamily { C70 } {#1} {#2} { m }  {#3}
    \CJKpunctmapfamily { C70 } {#1} {#2} { it } {#3}
    \CJKpunctmapfamily { C70 } {#1} {#2} { sl } {#3}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_punct_map_itshape:nn}
% CJK 族 |#1| 的 \tn{itshape} 使用族 |#2| 的边界信息。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_punct_map_itshape:nn #1#2
  {
    \CJKpunctmapfamily { C19 } {#1} { m }  { it } {#2}
    \CJKpunctmapfamily { C19 } {#1} { b }  { it } {#2}
    \CJKpunctmapfamily { C19 } {#1} { bx } { it } {#2}
    \CJKpunctmapfamily { C70 } {#1} { m }  { it } {#2}
    \CJKpunctmapfamily { C70 } {#1} { b }  { it } {#2}
    \CJKpunctmapfamily { C70 } {#1} { bx } { it } {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% 载入边界信息文件。
%     \begin{macrocode}
\ctex_file_input:n { ctexspa.def }
%    \end{macrocode}
%
%    \begin{macrocode}
%</pdftex>
%<*xetex>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-xetex.def}}
%
%    \begin{macrocode}
\RequirePackage { xeCJK }
\exp_args:Nx \xeCJKsetup
  {
    AutoFakeBold = true ,
    PunctStyle   = \l_@@_punct_tl
  }
%    \end{macrocode}
%
% 最新版本的 \pkg{fontspec} 默认对 \tn{rmfamily} 和 \tn{sffamily} 设置
% |Ligatures=TeX|，对 \tn{ttfamily} 设置 |WordSpace={1,0,0}| 和
% |PunctuationSpace=WordSpace|。
%    \begin{macrocode}
\@ifpackagelater { fontspec } { 2014/05/25 } { }
  { \msg_error:nnn { ctex } { package-too-old } { fontspec } }
%    \end{macrocode}
%
%    \begin{macrocode}
%</xetex>
%<*luatex>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-luatex.def}}
%
% \changes{v2.0}{2014/03/08}{通过 \pkg{luatexja} 宏包支持 \LuaLaTeX。}
%
% \pkg{luatexja} 为了兼容 p\LaTeX 的使用习惯，对 \LaTeXe 的 \pkg{NFSS} 作了不少
% 修改和扩充，这对于简体中文用户来说不是必要的。我们在这里禁用它。
%    \begin{macrocode}
\msg_new:nnn { ctex } { luatexja-loaded }
  {
    Package~`luatexja'~can~not~be~loaded~before~`ctex'.\\
    Loading~file~`#1'~will~abort!
  }
\@ifpackageloaded { luatexja }
  { \msg_critical:nnx { ctex } { luatexja-loaded } { \g_file_current_name_tl } }
  { \cs_new_eq:cN { ver@ltj-latex.\@pkgextension } \ExplFileDate }
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { luatexja } [ 2013/05/14 ]
\RequirePackage { fontspec }
%    \end{macrocode}
%
%    \begin{macrocode}
\@ifpackagelater { fontspec } { 2014/05/25 } { }
  { \msg_error:nnn { ctex } { package-too-old } { fontspec } }
%    \end{macrocode}
%
% \paragraph{\pkg{luatexja} 的默认设置}
%
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
% 以下设置抄录自 \file{lltjdefs.sty}。
%    \begin{macrocode}
\ltjdefcharrange{1}{"80-"36F, "1E00-"1EFF}
\ltjdefcharrange{2}{"370-"4FF, "1F00-"1FFF}
\ltjdefcharrange{3}{%
  "2000-"243F, "2500-"27BF, "2900-"29FF, "2B00-"2BFF}
\ltjdefcharrange{4}{%
   "500-"10FF, "1200-"1DFF, "2440-"245F, "27C0-"28FF, "2A00-"2AFF,
  "2C00-"2E7F, "4DC0-"4DFF, "A4D0-"A82F, "A840-"ABFF, "FB00-"FE0F,
  "FE20-"FE2F, "FE70-"FEFF, "10000-"1FFFF, "E000-"F8FF} % non-Japanese
\ltjdefcharrange{5}{"D800-"DFFF, "E0000-"E00FF, "E01F0-"10FFFF}
\ltjdefcharrange{6}{%
  "2460-"24FF, "2E80-"2EFF, "3000-"30FF, "3190-"319F, "31F0-"4DBF,
  "4E00-"9FFF, "F900-"FAFF, "FE10-"FE6F, "20000-"2FFFF, "E0100-"E01EF}
\ltjdefcharrange{7}{
  "1100-"11FF, "2F00-"2FFF, "3100-"31EF, "A000-"A4CF, "A830-"A83F,
  "AC00-"D7FF}
\ltjdefcharrange{8}{"A7, "A8, "B0, "B1, "B4, "B6, "D7, "F7}
\ltjsetparameter{jacharrange={-1, +2, +3, -4, -5, +6, +7, +8}}
\directlua{for x=128,255 do luatexja.math.is_math_letters[x] = true end}
%    \end{macrocode}
%
% 以下设置抄录自 \file{ltj-latex.sty}。
%    \begin{macrocode}
\directlua{
  local s = kpse.find_file('ltj-kinsoku.lua', 'tex')
  luatexja.stack.charprop_stack_table[0] = s and dofile(s) or {}
}
\ltjsetparameter{kanjiskip=0pt plus 0.4pt minus 0.4pt,
  xkanjiskip=.25\zw plus 1pt minus 1pt,
  autospacing, autoxspacing, jacharrange={-1},
  yalbaselineshift=0pt, yjabaselineshift=0pt,
  jcharwidowpenalty=500, differentjfm=paverage
}
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
% \paragraph{\pkg{luatexja} 的补丁}
%
%    \begin{macrocode}
%<@@=ctex_ltj>
%    \end{macrocode}
%
% 在 \LaTeX{} 下，\pkg{luatexja} 对 \pkg{fontspec}、\pkg{xunicode}、\pkg{unicode-math}
% 和 \pkg{listings} 打了补丁。其中前三个是把 \cs{char} 换成 \cs{ltjalchar}，确保
% 字符是 ALchar 类。我们这里用 \pkg{xunicode-addon} 来处理 \pkg{xunicode}。
%    \begin{macrocode}
\RequirePackage { xunicode-addon }
\AtBeginUTFCommand
  {
    \group_begin:
    \ctex_lua_now_x:n { tex.globaldefs = 0 }
    \ltj@allalchar
  }
\AtEndUTFCommand { \group_end: }
%    \end{macrocode}
% 对 \pkg{fontspec} 沿用 \pkg{luatexja} 的补丁。
%    \begin{macrocode}
\RequirePackage { lltjp-fontspec }
%    \end{macrocode}
% \pkg{lltjp-unicode-math} 让数学符号命令成为普通的文字宏。为了避免它被展开，应该
% 用 \cs{protected} 来定义。
%    \begin{macrocode}
\group_begin:
\char_set_catcode_other:n { \c_zero }
\cs_new_protected:Npn \@@_um_char:Nw #1 = #2 \q_nil
  {
    \group_begin:
      \char_set_lccode:nn { \c_zero } {#2}
      \tex_lowercase:D
        {
          \group_end:
          \cs_gset_protected_nopar:Npn #1
            {
              \mode_if_math:TF { ^^@ }
                { {
                    \ctex_lua_now_x:n { tex.globaldefs = 0 }
                    \ltj@allalchar ^^@
                } }
            }
        }
    \ltjsetmathletter {#2}
  }
\group_end:
\AfterPreamble
  {
    \cs_if_free:NF \um_cs_set_eq_active_char:Nw
      { \cs_set_eq:NN \um_cs_set_eq_active_char:Nw \@@_um_char:Nw }
  }
%    \end{macrocode}
% 对 \pkg{listings} 的补丁是让代码环境支持 JAchar 类。\pkg{luatexja} 的补丁会将
% 代码目录标题改为日文，我们不需要。
%    \begin{macrocode}
\AfterPreamble
  {
    \@ifpackageloaded { listings }
      {
        \use:x
          {
            \exp_not:N \RequirePackage { lltjp-listings }
            \tl_set:Nn \exp_not:N \lstlistingname
              { \exp_not:o { \lstlistingname } }
            \tl_set:Nn \exp_not:N \lstlistlistingname
              { \exp_not:o { \lstlistlistingname } }
          }
      } { }
  }
%    \end{macrocode}
%
% \paragraph{字体切换方式}
%
% \begin{macro}[internal]{\ctex_ltj_select_font:,\CJK@family}
% \cs{CJK@family} 保存的是当前 CJK 实际的字体族名，如果为空表示没有设置过字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_select_font:
  {
    \cs_if_exist_use:cF { \l_@@_current_font_tl }
      { \tl_if_empty:NF \CJK@family { \@@_select_font_aux: } }
  }
\tl_new:N \CJK@family
\tl_new:N \l_@@_current_font_tl
\tl_set:Nn \l_@@_current_font_tl
  { \CJK@encoding / \CJK@family / \f@series / \f@shape / \f@size }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_select_font_aux:}
% 使用 \cs{pickup@font} 取得字体名称前，总需要先设置 \cs{font@name}。在这里将
% \cs{f@family} 换成 CJK 字体族，并确保编码正确。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_select_font_aux:
  {
    \group_begin:
      \tl_set_eq:NN \f@encoding \CJK@encoding
      \tl_set_eq:NN \f@family \CJK@family
      \@@_push_fontname:n { \use:c { \curr@fontshape / \f@size } }
      \ctex_ltj_pickup_font:
    \group_end:
    \font@name
    \@@_pop_fontname:
%    \end{macrocode}
% 当字形未定义的时候，\textsf{NFSS} 就会启动替换机制（\cs{wrong@fontshape}）。
% 第一次启动后，\cs{l_@@_current_font_tl} 还是没有定义。为此，我们再次选择字体，
% 确保它有定义和指向正确的 \texttt{font.id}。这对 \opt{AlternateFont} 的设置
% 特别重要。
%    \begin{macrocode}
    \cs_if_exist:cF { \l_@@_current_font_tl }
      { \@@_select_font_aux: }
  }
\cs_new_protected_nopar:Npn \@@_push_fontname:n #1
  {
    \cs_gset_eq:NN \@@_save_fontname:w \font@name
    \cs_gset_nopar:Npx \font@name {#1}
  }
\cs_new_protected_nopar:Npn \@@_pop_fontname:
  { \cs_gset_eq:NN \font@name \@@_save_fontname:w }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_pickup_font:}
% 替换 \cs{define@newfont} 内部调用的 \cs{extract@font} 和 \cs{do@subst@correction}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_pickup_font:
  {
    \exp_after:wN \cs_if_exist:NF \font@name
      {
        \group_begin:
          \cs_set_eq:NN \extract@font \ctex_ltj_extract_font:
          \cs_set_eq:NN \do@subst@correction \ctex_ltj_subst_font:
          \define@newfont
        \group_end:
      }
  }
\cs_new_eq:NN \pickup@jfont \ctex_ltj_pickup_font:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_extract_font:}
% \pkg{luatexja} 的 \cs{globaljfont} 在 \pkg{luatexja-core} 中定义：
% \begin{verbatim}
%   %%%%%%%% \jfont\CS={...:...;jfm=metric;...}, \globaljfont
%   \protected\def\jfont{\afterassignment\ltj@@jfont\directlua{luatexja.jfont.jfontdefX(false)}}
%   \protected\def\globaljfont{%
%   \afterassignment\ltj@@jfont\directlua{luatexja.jfont.jfontdefX(true)}}
%   \def\ltj@@jfont{\directlua{luatexja.jfont.jfontdefY()}}
% \end{verbatim}
% \texttt{jfontdefX} 函数的作用是把 \cs{CS} 定义为其后的字体，\texttt{jfontdefY}
% 的作用是更新 \texttt{JFM} 和记录相关字体信息。最后的工作是：
% \begin{verbatim}
%   tex.sprint(cat_lp, global_flag .. '\\protected\\expandafter\\def\\csname '
%     .. cstemp  .. '\\endcsname{\\ltj@curjfnt=' .. fn .. '\\relax}')
% \end{verbatim}
% \cs{CS} 的作用就是把 \cs{ltj@curjfnt} 设置为刚才定义的字体的 \texttt{font.id}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_extract_font:
  {
    \get@external@font
    \ctex_ltj_if_alternate_shape_exist:nT { \curr@fontshape }
      {
        \tl_set:Nx \external@font
          { \exp_after:wN \@@_patch_external_font:w \external@font }
      }
    \exp_after:wN \globaljfont \font@name \external@font \scan_stop:
%    \end{macrocode}
% 这里 \cs{font@name} 不会直接改变当前字体，而 \cs{DeclareFontFamily} 和
% \cs{DeclareFontShape} 的最后一个参数通常要使用 \cs{font} 来引用当前字体。
% 为此，我们在分组内启用之前定义的字体，以便能得到正确的 \cs{font}。对字体参数的
% 赋值总是全局的，不会受到分组的影响。
%    \begin{macrocode}
    \font@name
    \ctex_lua_now_x:n { font.current(tex.attribute['ltj@curjfnt']) }
    \use:c { \f@encoding + \f@family }
    \use:c { \curr@fontshape }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_subst_font:}
% \cs{do@subst@correction} 在设置通过 \texttt{sub} 或者 \texttt{ssub} 函数定义的
% 字体时会用到。如果没有设置 \opt{SlantedFont}，\pkg{fontspec} 会设置
% \cs{itdefault} 作为 \cs{sldefault} 的替代字形，因而会用到这个函数。它的本来定义是：
% \begin{verbatim}
%   \def\do@subst@correction{%
%       \xdef\subst@correction{%
%          \font@name
%          \global\expandafter\font
%            \csname \curr@fontshape/\f@size\endcsname
%            \noexpand\fontname\font
%           \relax}%
%       \aftergroup\subst@correction
%   }
% \end{verbatim}
% 我们在这里不需要定义新字体，而是设置对应字体的命令。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_subst_font:
  {
    \ctex_ltj_if_alternate_shape_exist:nF { \curr@fontshape }
      {
        \group_begin:
        \tl_set_eq:NN \CJK@family \f@family
        \cs_if_exist:cF { \l_@@_current_font_tl  }
          {
            \cs_gset_protected_nopar:Npx \subst@correction
              {
                \cs_new_eq:NN
                  \exp_not:c { \l_@@_current_font_tl }
                  \font@name
              }
            \group_insert_after:N \group_insert_after:N
            \group_insert_after:N \subst@correction
          }
        \group_end:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,TF]{\ctex_ltj_if_alternate_shape_exist:n}
% 即 \cs{luatexja} 中的 |\ltj@@does@alt@set|，判断是否存在替代字体。
%    \begin{macrocode}
\prg_new_conditional:Npnn \ctex_ltj_if_alternate_shape_exist:n #1 { T , F , TF }
  {
    \ctex_lua_now_x:n { luatexja.jfont.does_alt_set ('\luatexluaescapestring {#1}') }
      \prg_return_true: \else: \prg_return_false: \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_patch_external_font:w}
% 若对字体的定义完全相同，则它们有相同的 \texttt{font.id}。因此如果字形是由
% \textsf{NFSS} 的替换机制定义的，它们就有相同的 \texttt{font.id}。
% |print_aftl_address| 函数的定义是
% \begin{verbatim}
%   function print_aftl_address()
%     tex.sprint(cat_lp, ';ltjaltfont' .. tostring(aftl_base):sub(8))
%   end
% \end{verbatim}
% 主要目的是，如果当前字形有替代字体，则往字形的定义中加入一些标志，确保
% \texttt{font.id} 唯一。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_patch_external_font:w #1 ~ at
  { #1 \ctex_lua_now_x:n { luatexja.jfont.print_aftl_address() } ~ at }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_select_alternate_font:}
% 在 \cs{selectfont} 中更新替代字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_select_alternate_font:
  {
    \ctex_ltj_if_alternate_shape_exist:nT { \l_@@_current_shape_tl }
      {
        \ctex_lua_now_x:n
          {
            luatexja.jfont.output_alt_font_cmd
              ('\luatexluaescapestring { \l_@@_current_shape_tl }')
          }
        \ctex_lua_now_x:n { luatexja.jfont.pickup_alt_font_a ('\f@size') }
      }
  }
\tl_new:N \l_@@_current_shape_tl
\tl_set:Nn \l_@@_current_shape_tl
  { \CJK@encoding / \CJK@family / \f@series / \f@shape }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ltj@pickup@altfont@aux}
% 被用在函数 |output_alt_font_cmd| 中，作用是定义替代字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ltj@pickup@altfont@aux #1
  {
    \cs_if_exist:cF { #1/\f@size }
      {
        \group_begin:
          \use:x { \exp_not:N \split@name #1 / \f@size } \@nil
          \@@_push_fontname:n { \use:c { \curr@fontshape / \f@size } }
          \ctex_ltj_pickup_font:
        \group_end:
        \@@_pop_fontname:
      }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
% \begin{macro}[internal]{\ltj@pickup@altfont@copy}
% 被用在函数 |pickup_alt_font_a| 中。|ltj@@getjfontnumber| 的作用是将字体命令
% |#1| 对应的 \texttt{font.id} 保存到 \cs{ltj@tempcntc} 中。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ltj@pickup@altfont@copy #1#2
  {
    \ltj@@getjfontnumber #1
    \ctex_lua_now_x:n
      {
        luatexja.jfont.pickup_alt_font_b
          ( \the\ltj@tempcntc, '\luatexluaescapestring {#2}' )
      }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
% 以下内容抄录自 \file{lltjfont.sty}，目的是让汉字可以在数学环境中直接使用。
%    \begin{macrocode}
\def\ltj@@IsFontJapanese#1{%
  \directlua{luatexja.jfont.is_kenc(string.match(
      '\luatexluaescapestring{#1}', '[^/]+'))}}
{\catcode`M=12%
\gdef\ltj@@mathJapaneseFonts#1M#2#3\relax{\ltj@@IsFontJapanese{#3}}}
\let\ltj@@al@getanddefine@fonts=\getanddefine@fonts
\def\ltj@@ja@getanddefine@fonts#1#2{%
  \xdef\font@name{\csname \string#2/\tf@size\endcsname}%
  \pickup@jfont\let\textfont@name\font@name
  \xdef\font@name{\csname \string#2/\sf@size\endcsname}%
  \pickup@jfont\let\scriptfont@name\font@name
  \xdef\font@name{\csname \string#2/\ssf@size\endcsname}%
  \pickup@jfont
  \edef\math@fonts{\math@fonts\ltj@setpar@global%
    \ltj@@set@stackfont#1,\textfont@name:{MJT}%
    \ltj@@set@stackfont#1,\scriptfont@name:{MJS}%
    \ltj@@set@stackfont#1,\font@name:{MJSS}%
  }%
}
\def\getanddefine@fonts#1#2{%
  \ltj@tempcnta=#1\ltj@@IsFontJapanese{\string#2}%
  \ifin@\let\ltj@temp=\ltj@@ja@getanddefine@fonts%
  \else \let\ltj@temp=\ltj@@al@getanddefine@fonts\fi
  \ltj@temp{#1}{#2}%
}
\def\use@mathgroup#1#2{\relax\ifmmode
  \math@bgroup
    \expandafter\ifx\csname M@\f@encoding\endcsname#1\else
    #1\fi\ltj@tempcnta=#2 \expandafter\ltj@@mathJapaneseFonts\string#1\relax%
    \ifin@\jfam#2\relax\else\mathgroup#2\relax\fi
  \expandafter\math@egroup\fi}%
%    \end{macrocode}
%
%    \begin{macrocode}
\let\@@italiccorr=\/
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=ctex_ltj>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
% \begin{macro}[internal]{\g_@@_jfm_tl}
% \pkg{luatexja} 中与标点格式 \opt{plain} 对应的 \texttt{JFM} 是 \opt{mono}。
%    \begin{macrocode}
\tl_new:N \g_@@_jfm_tl
\tl_gset:Nx \g_@@_jfm_tl
  {
    \str_if_eq_x:nnTF { \l__ctex_punct_tl } { plain }
      { mono } { \l__ctex_punct_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\CJK@encoding,\@@_change_encoding:}
% 在 \LaTeX 下，\pkg{luatexja} 依赖字体编码来实现特殊设置。例如上述的
% |\ltj@@IsFontJapanese| 就是通过判断编码来实现的，它在设置数学字体时会用到。所以
% 不应该与西文共用 \texttt{EU2}。定义字体族 song 为 \cs{CJK@encoding} 的默认替换
% 字体。下划线 |_| 不在 \cs{nfss@catcodes} 里，可以放心使用。
%    \begin{macrocode}
\tl_const:Nn \CJK@encoding { LTJY3 }
\DeclareFontEncoding { \CJK@encoding } { } { }
\DeclareFontSubstitution { LTJY3 } { song } { \mddefault } { \updefault }
\ctex_lua_now_x:n { luatexja.jfont.add_kyenc_list('\CJK@encoding') }
\cs_new_protected_nopar:Npn \@@_change_encoding:
  { \tl_set_eq:NN \g_fontspec_encoding_tl \CJK@encoding }
\DeclareFontFamily { \CJK@encoding } { song } { }
\DeclareFontShape { \CJK@encoding } { song } { \mddefault } { \updefault }
  { <-> psft:SimSun:cid=Adobe-GB1-5;jfm=\g_@@_jfm_tl } { }
\DeclareFontShape { \CJK@encoding } { song } { \bfdefault } { \updefault }
  { <-> psft:SimHei:cid=Adobe-GB1-5;jfm=\g_@@_jfm_tl } { }
\tl_const:Nn \c_@@_math_tl { CJKmath }
\DeclareSymbolFont { \c_@@_math_tl }
  { \CJK@encoding } { song } { \mddefault } { \updefault }
\SetSymbolFont { \c_@@_math_tl } { bold }
  { \CJK@encoding } { song } { \bfdefault } { \updefault }
\int_const:Nn \c_@@_math_fam_int { \use:c { sym \c_@@_math_tl } }
\jfam \c_@@_math_fam_int
%    \end{macrocode}
% \end{macro}
%
% \paragraph{字体族的定义与使用}
%
% 这是 \pkg{luatexja-fontspec} 中新增的一些字体选项。
%    \begin{macrocode}
\newfontfeature { CID }     {    cid = #1 }
\newfontfeature { JFM }     {    jfm = #1 }
\newfontfeature { JFM-var } { jfmvar = #1 }
%    \end{macrocode}
%
% 在新版本的 \pkg{fontspec} 中，\cs{__fontspec_namewrap:n} 变成了私有函数。
%    \begin{macrocode}
\keys_define:nn { fontspec-preparse-external }
  {
    NoEmbed .code:n =
      { \cs_set_eq:NN \__fontspec_namewrap:n \@@_noembed_wrap:n }
  }
\cs_new:Npn \@@_noembed_wrap:n #1 { psft: #1 }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_ltj_set_family:nnn}
% 将自定义的字体族名与 \pkg{fontspec} 实际设置的名字对应起来。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_family:nnn #1#2#3
  {
    \group_begin:
    \clist_clear:N \l_@@_char_range_clist
    \seq_clear:N \l_@@_alternate_seq
    \tl_set:Nn \l_@@_base_CJKfamily_tl {#1}
    \keys_set_known:nnN { ctex_ltj / fontspec } {#2} \l_@@_tmp_tl
    \clist_set:No \l_@@_font_options_clist { \l_@@_tmp_tl }
    \ctex_ltj_set_alternate_family:nnF {#1} {#3}
      {
        \prop_gput:Nnn \g_@@_family_font_name_prop {#1} {#3}
        \prop_gput:Nno \g_@@_family_font_options_prop
          {#1} { \l_@@_font_options_clist }
        \@@_update_family_uid:N \l_@@_font_options_clist
        \@@_use_global_options:N \l_@@_font_options_clist
        \@@_gset_family_cs:nn {#1} {#3}
      }
    \group_end:
  }
\cs_new_protected:Npn \ctex_ltj_set_family:xxx #1#2#3
  { \use:x { \ctex_ltj_set_family:nnn {#1} {#2} {#3} } }
\tl_new:N \l_@@_base_CJKfamily_tl
\clist_new:N \l_@@_font_options_clist
\cs_new_protected_nopar:Npn \@@_use_global_options:N #1
  {
    \clist_concat:NNN #1 \g_@@_default_features_clist #1
    \clist_put_left:Nx #1 { JFM = \g_@@_jfm_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}[internal]
%  {\g_@@_family_name_prop,\g_@@_family_font_name_prop,\g_@@_family_font_options_prop}
% 分别保存 \pkg{fontspec} 设置的字体族名、字体名称和字体选项。
%    \begin{macrocode}
\prop_new:N \g_@@_family_name_prop
\prop_new:N \g_@@_family_font_name_prop
\prop_new:N \g_@@_family_font_options_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[internal]{\@@_check_family:n}
% 删除重复的定义，清除替代字体的先前设置。
%   \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_check_family:n #1
  {
    \prop_gpop:NnNT \g_@@_family_font_name_prop {#1} \l_@@_tmp_tl
      {
        \cs_undefine:c { \@@_family_csname:n {#1} }
        \cs_undefine:c { \@@_alternate_cs:n {#1} }
        \prop_gpop:NnNT \g_@@_family_name_prop {#1} \l_@@_base_family_tl
          {
            \use:c { \@@_alternate_cs:n { clear / #1 } }
            \cs_undefine:c { \@@_alternate_cs:n { clear / #1 } }
            \cs_undefine:c { \@@_alternate_cs:n { reset / #1 } }
            \prop_gremove:Nn \g_@@_reset_alternate_prop {#1}
          }
        \msg_warning:nnxx { ctex } { redefine-family } {#1} { \l_@@_tmp_tl }
      }
  }
\tl_new:N \l_@@_tmp_tl
\msg_new:nnn { ctex } { redefine-family }
  { Redefining~CJKfamily~`\@@_msg_family_map:n {#1}'~(#2). }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_gset_family_cs:nn}
% 在设置字体时，实际上并不是马上就定义。而是只保存相关参数，在通过 \cs{CJKfamily}
% 第一次使用时才定义。需要注意将编码改为 \cs{CJK@encoding}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_gset_family_cs:nn #1#2
  {
    \cs_gset_protected_nopar:cpx { \@@_family_csname:n {#1} }
      {
        \group_begin:
        \@@_change_encoding:
        \exp_not:n { \cs_set_eq:NN \CJKfamily \use_none:n }
        \exp_not:n { \fontspec_set_family:Nnn \g_@@_fontspec_family_tl }
          { \exp_not:o { \l_@@_font_options_clist } } {#2}
        \prop_gput:Nno \exp_not:N \g_@@_family_name_prop {#1}
          { \exp_not:N \g_@@_fontspec_family_tl }
        \tl_gset_eq:NN \exp_not:N \g_@@_fontspec_family_tl
          \exp_not:N \g_@@_fontspec_family_tl
        \@@_set_alternate_family:n {#1}
        \group_end:
      }
  }
\tl_new:N \l_@@_base_family_tl
\tl_new:N \g_@@_fontspec_family_tl
\cs_new_nopar:Npn \@@_family_csname:n #1 { ctex_ltj/family/#1 }
\cs_new_protected_nopar:Npn \@@_set_alternate_family:n #1
  {
    \tl_set:Nn \l_@@_base_CJKfamily_tl {#1}
    \tl_set_eq:NN \l_@@_base_family_tl \g_@@_fontspec_family_tl
    \cs_if_exist_use:c { \@@_alternate_cs:n { reset / #1 } }
    \cs_if_exist_use:c { \@@_alternate_cs:n {#1} }
  }
\cs_new:Npn \@@_alternate_cs:n #1 { ctex_ltj/alternate_family/#1 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\CJKfamily}
% 切换字体。
%    \begin{macrocode}
\NewDocumentCommand \CJKfamily { m }
  { \ctex_ltj_switch_family:x {#1} \tex_ignorespaces:D }
\cs_new_protected_nopar:Npn \ctex_ltj_switch_family:n #1
  {
    \ctex_ltj_family_if_exist:xNTF {#1} \CJK@family
      {
        \tl_set:Nn \l_ctex_ltj_family_tl {#1}
        \selectfont
      }
      { \@@_family_unknown_warning:n {#1} }
  }
\tl_new:N \l_ctex_ltj_family_tl
\cs_generate_variant:Nn \ctex_ltj_switch_family:n { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,TF]{\ctex_ltj_family_if_exist:n}
% 判断 CJK 字体族 |#1| 是否存在，若存在则把实际族名保存到 |#2| 中。
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \ctex_ltj_family_if_exist:xN #1#2 { T , F , TF }
  {
    \prop_get:NxNTF \g_@@_family_name_prop {#1} #2
      { \prg_return_true: }
      {
        \cs_if_exist_use:cTF { \@@_family_csname:n {#1} }
          {
            \tl_set_eq:NN #2 \g_@@_fontspec_family_tl
            \prg_return_true:
          }
          { \prg_return_false: }
      }
  }
\cs_generate_variant:Nn \prop_get:NnNTF { Nx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_family_unknown_warning:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_family_unknown_warning:n #1
  {
    \prop_if_empty:NF \g_@@_family_font_name_prop
      {
        \seq_if_in:NnF \g_@@_unknown_family_seq {#1}
          {
            \seq_gput_right:Nn \g_@@_unknown_family_seq {#1}
            \msg_warning:nnn { ctex } { family-unknown } {#1}
          }
      }
  }
\seq_new:N \g_@@_unknown_family_seq
\msg_new:nnn { ctex } { family-unknown }
  {
    Unknown~CJK~family~`\@@_msg_family_map:n {#1}'~is~being~ignored.\\
    Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it.
  }
\cs_new_nopar:Npn \@@_msg_def_family_map:n #1
  {
    \str_case_x:nnF {#1}
      {
        \CJKrmdefault { \token_to_str:N \setCJKmainfont }
        \CJKsfdefault { \token_to_str:N \setCJKsansfont }
        \CJKttdefault { \token_to_str:N \setCJKmonofont }
      }
      { \token_to_str:N \setCJKfamilyfont \{ #1 \} }
    [...]\{...\}
  }
\cs_new_nopar:Npn \@@_msg_family_map:n #1
  {
    \str_case_x:nnF {#1}
      {
        \CJKrmdefault { \token_to_str:N \CJKrmdefault }
        \CJKsfdefault { \token_to_str:N \CJKsfdefault }
        \CJKttdefault { \token_to_str:N \CJKttdefault }
      }
      {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_fontspec:nn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_fontspec:nn #1#2
  {
    \prop_get:NnNTF \g_@@_fontspec_prop
      { CJKfontspec/#1/#2/id } \l_ctex_ltj_family_tl
      { \ctex_ltj_switch_family:x { \l_ctex_ltj_family_tl } }
      {
        \int_gincr:N \g_@@_family_int
        \@@_fontspec:xnn
          { CJKfontspec ( \int_use:N \g_@@_family_int ) }
          {#1} {#2}
      }
  }
\cs_new_protected_nopar:Npn \ctex_ltj_fontspec:xx #1#2
  { \use:x { \ctex_ltj_fontspec:nn {#1} {#2} } }
\cs_new_protected_nopar:Npn \@@_fontspec:nnn #1#2#3
  {
    \bool_if:NT \l_@@_add_alternate_bool
      {
        \cs_if_free:cF
          { \@@_alternate_cs:n { reset / \l_ctex_ltj_family_tl } }
          {
            \cs_gset_eq:cc
              { \@@_alternate_cs:n { reset / #1 } }
              { \@@_alternate_cs:n { reset / \l_ctex_ltj_family_tl } }
            \cs_gset_eq:cc
              { \@@_alternate_cs:n { clear / #1 } }
              { \@@_alternate_cs:n { clear / \l_ctex_ltj_family_tl } }
          }
        \bool_set_false:N \l_@@_add_alternate_bool
      }
    \prop_gput:Nnn \g_@@_fontspec_prop { CJKfontspec/#2/#3/id } {#1}
    \ctex_ltj_set_family:nnn {#1} {#2} {#3}
    \ctex_ltj_switch_family:n {#1}
  }
\cs_generate_variant:Nn \@@_fontspec:nnn { x }
\prop_new:N \g_@@_fontspec_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\ctex_ltj_add_font_features:n,\ctex_ltj_add_font_features:nn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_add_font_features:n #1
  { \ctex_ltj_add_font_features:xn { \l_ctex_ltj_family_tl } {#1} }
\cs_new_protected_nopar:Npn \ctex_ltj_add_font_features:nn #1#2
  {
    \prop_get:NnNTF \g_@@_family_font_name_prop
      {#1} \l_@@_tmp_tl
      {
        \prop_get:NnN \g_@@_family_font_options_prop
          {#1} \l_@@_font_options_clist
        \clist_put_right:Nn \l_@@_font_options_clist {#2}
        \bool_set_true:N \l_@@_add_alternate_bool
        \ctex_ltj_fontspec:xx
          { \exp_not:o { \l_@@_font_options_clist } }
          { \exp_not:o { \l_@@_tmp_tl } }
      }
      { \msg_warning:nn { ctex } { addCJKfontfeature-ignored } }
  }
\bool_new:N \l_@@_add_alternate_bool
\cs_generate_variant:Nn \ctex_ltj_add_font_features:n  { x }
\cs_generate_variant:Nn \ctex_ltj_add_font_features:nn { x }
\msg_new:nnn { ctex } { addCJKfontfeature-ignored }
  {
    \token_to_str:N \addCJKfontfeature (s)~ignored.\\
    It~cannot~be~used~with~a~font~that~wasn't~selected~by~ctex.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\setCJKfamilyfont,\newCJKfontfamily,\CJKfontspec,\addCJKfontfeatures}
%    \begin{macrocode}
\NewDocumentCommand \setCJKfamilyfont { m O { } m }
  { \ctex_ltj_set_family:xxx {#1} {#2} {#3} }
\NewDocumentCommand \newCJKfontfamily { o m O { } m }
  {
    \tl_set:Nx \l_@@_tmp_tl
      { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} }
    \cs_new_protected_nopar:Npx #2
      { \ctex_ltj_switch_family:n { \l_@@_tmp_tl } }
    \ctex_ltj_set_family:xxx { \l_@@_tmp_tl } {#3} {#4}
  }
\NewDocumentCommand \CJKfontspec { O { } m }
  {
    \ctex_ltj_fontspec:xx {#1} {#2}
    \tex_ignorespaces:D
  }
\NewDocumentCommand \addCJKfontfeatures { m }
  {
    \ctex_ltj_add_font_features:x {#1}
    \tex_ignorespaces:D
  }
\cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\setCJKmainfont,\setCJKsansfont,\setCJKmonofont,
%  \setCJKmathfont,\defaultCJKfontfeatures}
%    \begin{macrocode}
\NewDocumentCommand \setCJKmainfont { O { } m }
  {
    \ctex_ltj_set_family:xxx { \CJKrmdefault } {#1} {#2}
    \normalfont
  }
\cs_new_eq:NN \setCJKromanfont \setCJKmainfont
\NewDocumentCommand \setCJKsansfont { O { } m }
  {
    \ctex_ltj_set_family:xxx { \CJKsfdefault } {#1} {#2}
    \normalfont
  }
\NewDocumentCommand \setCJKmonofont { O { } m }
  {
    \ctex_ltj_set_family:xxx { \CJKttdefault } {#1} {#2}
    \normalfont
  }
\NewDocumentCommand \setCJKmathfont { O { } m }
  { \ctex_ltj_set_family:xxx { \c_@@_math_tl } {#1} {#2} }
\NewDocumentCommand \defaultCJKfontfeatures { m }
  { \clist_gset:Nn \g_@@_default_features_clist {#1} }
\clist_new:N \g_@@_default_features_clist
\@onlypreamble \setCJKmainfont
\@onlypreamble \setCJKsansfont
\@onlypreamble \setCJKmonofont
\@onlypreamble \setCJKmathfont
\@onlypreamble \setCJKromanfont
\@onlypreamble \defaultCJKfontfeatures
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\tl_if_exist:NF \CJKfamilydefault
  { \tl_const:Nn \CJKfamilydefault { \CJKrmdefault } }
\tl_if_exist:NF \CJKrmdefault { \tl_const:Nn \CJKrmdefault { rm } }
\tl_if_exist:NF \CJKsfdefault { \tl_const:Nn \CJKsfdefault { sf } }
\tl_if_exist:NF \CJKttdefault { \tl_const:Nn \CJKttdefault { tt } }
\ctex_preto_cmd:NnTF \rmfamily { \CJKfamily { \CJKrmdefault } } { }
  { \ctex_patch_failure:N \rmfamily }
\ctex_preto_cmd:NnTF \sffamily { \CJKfamily { \CJKsfdefault } } { }
  { \ctex_patch_failure:N \sffamily }
\ctex_preto_cmd:NnTF \ttfamily { \CJKfamily { \CJKttdefault } } { }
  { \ctex_patch_failure:N \ttfamily }
\ctex_preto_cmd:NnTF \normalfont { \CJKfamily { \CJKfamilydefault } }
  { \cs_set_eq:NN \reset@font \normalfont }
  { \ctex_patch_failure:N \normalfont }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_ltj_ensure_default_family:}
% 在导言区结束确认 \cs{CJKfamilydefault} 确实存在。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_ensure_default_family:
  {
    \prop_if_empty:NF \g_@@_family_font_name_prop
      {
        \ctex_ltj_family_if_exist:xNF { \CJKfamilydefault } \l_@@_tmpa_tl
          {
            \str_if_eq_x:nnTF { \CJKfamilydefault } { \CJKrmdefault }
              { \use:n }
              {
                \ctex_ltj_family_if_exist:xNTF { \CJKrmdefault } \l_@@_tmpa_tl
                  { \tl_gset:Nn \CJKfamilydefault { \CJKrmdefault } \use_none:n }
                  { \use:n }
              }
              {
                \prop_map_inline:Nn \g_@@_family_font_name_prop
                  {
                    \prop_map_break:n
                      { \tl_gset_rescan:Nnn \CJKfamilydefault { } { ##1 } }
                  }
              }
          }
        \normalfont
        \ctex_ltj_update_mathfont:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_update_mathfont:}
% 更新数学字体为实际的字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_update_mathfont:
  {
    \ctex_ltj_family_if_exist:xNTF { \c_@@_math_tl } \l_@@_tmp_tl
      { \ctex_ltj_update_mathfont:n { \l_@@_tmp_tl } }
      {
        \ctex_ltj_family_if_exist:xNT { \CJKfamilydefault } \l_@@_tmp_tl
          { \ctex_ltj_update_mathfont:n { \l_@@_tmp_tl } }
      }
  }
\cs_new_protected_nopar:Npn \ctex_ltj_update_mathfont:n #1
  {
    \tl_const:Nx \c_@@_math_family_tl {#1}
    \DeclareSymbolFont { \c_@@_math_tl } { \CJK@encoding }
      { \c_@@_math_family_tl } { \mddefault } { \updefault }
    \cs_if_free:cTF
      { \CJK@encoding/\c_@@_math_family_tl/\bfdefault/\updefault }
      {
        \SetSymbolFont { \c_@@_math_tl } { bold } { \CJK@encoding }
          { \c_@@_math_family_tl } { \mddefault } { \updefault }
      }
      {
        \SetSymbolFont { \c_@@_math_tl } { bold } { \CJK@encoding }
          { \c_@@_math_family_tl } { \bfdefault } { \updefault }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{替代字体的设置}
%
% \begin{macro}{AlternateFont,CharRange}
% 设置替代字体的选项。
%    \begin{macrocode}
\keys_define:nn { ctex_ltj / fontspec }
  {
    AlternateFont  .code:n = \ctex_ltj_set_alternate_seq:n {#1} ,
    AlternateFont  .value_required: ,
    CharRange .clist_set:N = \l_@@_char_range_clist ,
    CharRange .value_required:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_seq:n}
% 我们使用 \verb=||= 作为替代字体序列的分隔标志。它可能被设置为活动字符，为此
% 需要先“消毒”，同时过滤掉空元素。
%    \begin{macrocode}
\group_begin:
\char_set_catcode_active:N \/
\char_set_lccode:nn { `\/ } { `\| }
\tex_lowercase:D
  {
    \group_end:
    \cs_new_protected:Npn \ctex_ltj_set_alternate_seq:n #1
      {
        \clist_if_empty:NT \l_@@_char_range_clist
          {
            \tl_set:Nn \l_@@_tmp_tl {#1}
            \tl_replace_all:Nnn \l_@@_tmp_tl { // } { || }
            \seq_set_split:NnV \l_@@_tmp_seq { || } \l_@@_tmp_tl
            \seq_set_filter:NNn \l_@@_tmp_seq \l_@@_tmp_seq
              { ! \tl_if_blank_p:n { ##1 } }
            \seq_concat:NNN \l_@@_alternate_seq
              \l_@@_alternate_seq \l_@@_tmp_seq
          }
      }
  }
\seq_new:N \l_@@_tmp_seq
\seq_new:N \l_@@_alternate_seq
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_family:nnF}
% 如果在字体的选项中设置了 \opt{CharRange}，则只设置替代字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_family:nnF #1#2#3
  {
    \clist_if_empty:NTF \l_@@_char_range_clist
      {
        \@@_check_family:n {#1}
        \seq_if_empty:NF \l_@@_alternate_seq
          { \ctex_ltj_save_alternate_seq:cn { \@@_alternate_cs:n {#1} } {#2} }
        #3
      }
      { \ctex_ltj_set_alternate_family:nn {#1} {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\ctex_ltj_save_alternate_seq:Nn,\ctex_ltj_save_alternate_seq:Nnnwn}
% 保存由 \opt{AlternateFont} 设置的替代字体序列。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_save_alternate_seq:Nn #1#2
  {
    \seq_map_inline:Nn \l_@@_alternate_seq
      { \ctex_ltj_save_alternate_seq:Nnnwnw #1 {#2} ##1 { } \q_stop }
  }
\cs_generate_variant:Nn \ctex_ltj_save_alternate_seq:Nn { c }
\NewDocumentCommand \ctex_ltj_save_alternate_seq:Nnnwnw
  { m m m +O{ } m u{ \q_stop } }
  {
    \clist_set:Nn \l_@@_char_range_clist {#3}
    \clist_set:Nn \l_@@_alternate_options_clist {#4}
    \@@_use_global_options:N \l_@@_alternate_options_clist
    \tl_if_blank:nTF {#5}
      { \tl_set:Nn \l_@@_tmp_tl {#2} }
      {
        \tl_set:Nn \l_@@_tmp_tl {#5}
        \tl_replace_all:Nnn \l_@@_tmp_tl { * } {#2}
      }
    \use:x
      {
        \ctex_ltj_save_alternate_family:Nnnn \exp_not:N #1
          { \exp_not:o { \l_@@_char_range_clist } }
          { \exp_not:o { \l_@@_alternate_options_clist } }
          { \exp_not:o { \l_@@_tmp_tl } }
      }
  }
\clist_new:N \l_@@_alternate_options_clist
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_family:nn}
% 设置选项 \opt{CharRange} 范围内的替代字体。如果已经定义了主字体，我们也马上
% 定义替代字体，否则只保存起来备用。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_family:nn #1#2
  {
    \@@_update_family_uid:N \l_@@_font_options_clist
    \@@_use_global_options:N \l_@@_font_options_clist
    \ctex_ltj_set_alternate_family:coonn
      { \@@_alternate_cs:n {#1} }
      { \l_@@_char_range_clist }
      { \l_@@_font_options_clist } {#2} {#1}
  }
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_family:Nnnnn #1#2#3#4#5
  {
    \prop_get:NnNT \g_@@_family_name_prop {#5} \l_@@_base_family_tl
      { \ctex_ltj_set_alternate_family:nnn {#2} {#3} {#4} }
    \ctex_ltj_save_alternate_family:Nnnn #1 {#2} {#3} {#4}
  }
\cs_generate_variant:Nn \ctex_ltj_set_alternate_family:Nnnnn { coo }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_save_alternate_family:Nnnn}
% 保存替代字体序列的定义，以备定义主字体时使用。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_save_alternate_family:Nnnn #1#2#3#4
  {
    \cs_if_exist:NF #1 { \cs_set_eq:NN #1 \prg_do_nothing: }
    \cs_gset_protected_nopar:Npx #1
      { \exp_not:o { #1 \ctex_ltj_set_alternate_family:nnn {#2} {#3} {#4} } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_family:nnn}
% 实际定义替代字体族。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_family:nnn #1#2#3
  {
    \group_begin:
    \@@_change_encoding:
    \cs_set_eq:NN \CJKfamily \use_none:n
    \ctex_ltj_swap_cs:NN
      \DeclareFontShape@ \ctex_ltj_declare_alternate_shape:nnnnnn
    \tl_set:Nn \l_@@_char_range_clist {#1}
    \fontspec_set_family:Nnn \l_@@_alternate_family_tl {#2} {#3}
    \group_end:
  }
\tl_new:N \l_@@_alternate_family_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_swap_cs:NN}
% 交换两个控制序列的意义。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_swap_cs:NN #1#2
  {
    \cs_set_eq:NN \@@_tmp:w #1
    \cs_set_eq:NN #1 #2
    \cs_set_eq:NN #2 \@@_tmp:w
    \cs_undefine:N \@@_tmp:w
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{LTJFONTUID,\@@_update_family_uid:N}
% \pkg{fontspec} 在一个字体族的选项和字体名称相同的时候，就不定义新字体。为了
% 避免混淆替代字体的设置，我们新定义一个虚拟的选项 \opt{LTJFONTUID}，确保
% \pkg{fontspec} 对 CJK 字体族总是定义新字体。
%    \begin{macrocode}
\keys_define:nn { fontspec } { LTJFONTUID .code:n = }
\cs_new_protected_nopar:Npn \@@_update_family_uid:N #1
  {
    \int_gincr:N \g_@@_family_int
    \clist_put_right:Nx #1 { LTJFONTUID = \int_use:N \g_@@_family_int }
  }
\int_new:N \g_@@_family_int
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_declare_alternate_shape:nnnnnn}
% 在定义替代字体的字形时，通过字符范围与主字体的对应字形关联起来。
% \tn{DeclareFontShape@} 一个有六个参数，我们只需要使用它的第三个参数 \meta{series}
% 和第四个参数 \meta{shape}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_declare_alternate_shape:nnnnnn #1#2#3#4#5#6
  {
    \ctex_ltj_declare_alternate_shape:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
    \ctex_ltj_set_alternate_shape:Nnnnnnn \l_@@_char_range_clist
      { \l_@@_base_family_tl } {#3} {#4}
      { \l_fontspec_family_tl } {#3} {#4}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_shape:Nnnnnnn}
% 与 \pkg{luatexja} 的 \cs{DeclareAlternateKanjiFont} 的功能类似，区别是固定编码
% 为 \cs{CJK@encoding}。这个设置总是全局的。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_shape:Nnnnnnn #1#2#3#4#5#6#7
  {
    \clist_map_inline:Nn #1
      {
        \prop_get:NnNTF \g_@@_char_range_prop { ##1 } \l_@@_char_range_tl
          {
            \ctex_ltj_set_alternate_shape:nnN { #2/#3/#4 } { #5/#6/#7 }
              \l_@@_char_range_tl
          }
          { \ctex_ltj_set_alternate_shape:nnn { #2/#3/#4 } { #5/#6/#7 } { ##1 } }
      }
    \@@_save_alternate_shape:cnn
      { \@@_alternate_cs:n { clear / \l_@@_base_CJKfamily_tl } }
      { luatexja.jfont.clear_alt_font_latex }
      { '\luatexluaescapestring { \CJK@encoding/#2/#3/#4 }' }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_shape:nnn}
% 我们使用 \texttt{->} 而不是像 \pkg{luatexja} 一样使用 \texttt{-} 作为区间的
% 分隔符。\pkg{luatexja} 支持使用负数来引用由 \texttt{JFM} 设置的字符类。如果
% 使用 \texttt{-} 作为分隔符，那么负数单独使用时，就需要把它放在两层花括号之内
% （例如 |{{-1}}|），或者使用类似 |{-1}-{-1}| 的形式才不会解释错误。
%    \begin{macrocode}
\NewDocumentCommand \ctex_ltj_set_alternate_shape:nnn
  { m m > { \SplitArgument { \c_one } { -> } } m }
  { \ctex_ltj_set_alternate_shape:nnnn {#1} {#2} #3 }
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_shape:nnnn #1#2#3#4
  {
    \ctex_ltj_set_alternate_shape:n
      {
        \IfNoValueTF {#4}
          { \int_eval:n {#3} , \int_eval:n {#3} , }
          {
            \int_eval:n { \tl_if_blank:nTF {#3} { "80 } {#3} } ,
            \int_eval:n { \tl_if_blank:nTF {#4} { "10FFFF } {#4} } ,
          }
        '\luatexluaescapestring { \CJK@encoding/#2 }' ,
        '\luatexluaescapestring { \CJK@encoding/#1 }'
      }
  }
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_shape:n #1
  {
    \ctex_lua_now_x:n { luatexja.jfont.set_alt_font_latex ( #1 ) }
    \@@_save_alternate_shape:cnn
      { \@@_alternate_cs:n { reset / \l_@@_base_CJKfamily_tl } }
      { luatexja.jfont.set_alt_font_latex } {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_set_alternate_shape:nnN}
% 若字符范围预先由 \texttt{declarecharrange} 声明，则可以直接使用。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_set_alternate_shape:nnN #1#2#3
  {
    \tl_map_inline:Nn #3
      {
        \ctex_ltj_set_alternate_shape:n
          {
            ##1 ,
            '\luatexluaescapestring { \CJK@encoding/#2 }' ,
            '\luatexluaescapestring { \CJK@encoding/#1 }'
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_save_alternate_shape:Nnn}
% 将实际设置的替换字形保存起来用于清除或恢复。
% 暂时令 \cs{l_@@_base_family_tl} 为 \cs{scan_stop:} 是让它不被展开，使得替换
% 字体的设置可以在 \cs{addCJKfontfeature} 中直接使用。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_save_alternate_shape:Nnn #1#2#3
  {
    \group_begin:
    \cs_if_exist:NF #1 { \cs_set_eq:NN #1 \prg_do_nothing: }
    \cs_set_eq:NN \l_@@_base_family_tl \scan_stop:
    \cs_set_eq:NN \luatexluaescapestring \scan_stop:
    \cs_gset_protected_nopar:Npx #1
      { \exp_not:o {#1} \exp_not:N \ctex_lua_now_x:n { #2 ( #3 ) } }
    \group_end:
  }
\cs_generate_variant:Nn \@@_save_alternate_shape:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{clearalternatefont,resetalternatefont}
% 清除和重置操作总是全局的。
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
    clearalternatefont    .code:n =
      { \clist_map_function:xN {#1} \ctex_ltj_clear_alternate_font:n } ,
    resetalternatefont    .code:n =
      { \clist_map_function:xN {#1} \ctex_ltj_reset_alternate_font:n } ,
    clearalternatefont .default:n = \l_ctex_ltj_family_tl ,
    resetalternatefont .default:n = \l_ctex_ltj_family_tl
  }
\cs_new_protected_nopar:Npn \ctex_ltj_clear_alternate_font:n #1
  {
    \group_begin:
      \ctex_ltj_family_if_exist:xNTF {#1} \l_@@_base_family_tl
        {
          \cs_if_exist_use:cT { \@@_alternate_cs:n { clear / #1 } }
            {
              \prop_gput:Nno \g_@@_reset_alternate_prop
                {#1} { \l_@@_base_family_tl }
              \tl_set_eq:NN \CJK@family \l_@@_base_family_tl
              \selectfont
            }
        }
        { \@@_family_unknown_warning:n {#1} }
    \group_end:
  }
\cs_new_protected_nopar:Npn \ctex_ltj_reset_alternate_font:n #1
  {
    \group_begin:
      \prop_gpop:NnNT \g_@@_reset_alternate_prop {#1} \CJK@family
        {
          \tl_set_eq:NN \l_@@_base_family_tl \CJK@family
          \use:c { \@@_alternate_cs:n { reset / #1 } }
          \selectfont
        }
    \group_end:
  }
\prop_new:N \g_@@_reset_alternate_prop
\cs_generate_variant:Nn \clist_map_function:nN { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{declarecharrange}
% 预先声明字符范围。
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
    declarecharrange .code:n = \ctex_ltj_declare_char_range:x {#1} ,
    declarecharrange .value_required:
  }
\cs_new_protected_nopar:Npn \ctex_ltj_declare_char_range:n #1
  { \clist_map_inline:nn {#1} { \@@_declare_char_range:nn ##1 } }
\cs_generate_variant:Nn \ctex_ltj_declare_char_range:n { x }
\cs_new_protected_nopar:Npn \@@_declare_char_range:nn #1#2
  { \use:x { \ctex_ltj_declare_char_range:nn { \tl_trim_spaces:n {#1} } } {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_declare_char_range:nn,\g_@@_char_range_prop}
% |#1| 是名字，|#2| 是范围。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_declare_char_range:nn #1#2
  {
    \tl_clear:N \l_@@_char_range_tl
    \clist_map_function:nN {#2} \ctex_ltj_save_char_range:n
    \prop_gput:Nno \g_@@_char_range_prop {#1} { \l_@@_char_range_tl }
    \ctex_ltj_def_char_range_key:n {#1}
    \tl_clear:N \l_@@_char_range_tl
  }
\tl_new:N \l_@@_char_range_tl
\prop_new:N \g_@@_char_range_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_save_char_range:n}
% 预先解释字符区间的意义。
%    \begin{macrocode}
\NewDocumentCommand \ctex_ltj_save_char_range:n
  { > { \SplitArgument { \c_one } { -> } } m }
  { \ctex_ltj_save_char_range:nn #1 }
\cs_new_protected_nopar:Npn \ctex_ltj_save_char_range:nn #1#2
  {
    \tl_put_right:Nx \l_@@_char_range_tl
      { {
          \IfNoValueTF {#2}
            { \int_eval:n {#1} , \int_eval:n {#1} }
            {
              \int_eval:n { \tl_if_blank:nTF {#1} { "80 } {#1} } ,
              \int_eval:n { \tl_if_blank:nTF {#2} { "10FFFF } {#2} }
            }
      } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_def_char_range_key:n}
% 在字体设置选项中定义字符范围键。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_def_char_range_key:n #1
  {
    \keys_if_exist:nnF { ctex_ltj / fontspec } {#1}
      {
        \keys_define:nn { ctex_ltj / fontspec }
          { #1 .code:n = \ctex_ltj_char_range_key:nn {#1} { ##1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_ltj_char_range_key:nn}
% 如果字符范围键没有值，则只设置的这个字符范围内的替代字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_char_range_key:nn #1#2
  {
    \tl_if_blank:nTF {#2}
      { \tl_set:Nn \l_@@_char_range_clist {#1} }
      {
        \clist_if_empty:NT \l_@@_char_range_clist
          {
            \tl_set:Nn \l_@@_tmp_tl { {#1} }
            \@@_char_range_parse_feature:w #2 \q_stop
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_char_range_parse_feature:w}
% 可以使用加方括号的方式，通过文件名来调用字体。这容易与字体选项混淆。例如，需要
% 将 |[simsun.ttc]| 设置为 \opt{range} 的主字体，就需要使用
% |range={{[simsun.ttc]}}| 或者 |[]{[simsun.ttc]}|。下面的目的是，支持直接使用
% |[simsun.ttc]| 和 |[...][simsun.ttc]|。
%    \begin{macrocode}
\NewDocumentCommand \@@_char_range_parse_feature:w
  { +o o u { \q_stop } }
  {
    \exp_args:NNf \tl_put_right:Nn \l_@@_tmp_tl
      {
        \IfNoValueTF {#1} { {#3} }
          {
            \IfNoValueTF {#2}
              { \tl_if_blank:nTF {#3} { { [#1] } } { [ {#1} ] {#3} } }
              { [ {#1} ] { [#2] } }
          }
      }
    \seq_put_right:No \l_@@_alternate_seq { \l_@@_tmp_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{其它设置}
%
% \begin{macro}[internal]{\ctex_ltj_update_xkanjiskip:,\l_@@_xkanjiskip_skip}
% \cs{ltjsetparameter} 对 \opt{xkanjiskip} 是即时赋值。\cs{zw} 与字体相关，因此
% 需要每次 \cs{selectfont} 的时候更新一次 \opt{xkanjiskip}。如果用户设置过
% \opt{xkanjiskip}，就不更新。注意，同 \TeX{} 的 \cs{baselineskip} 一样，如果在
% 一个段落内多次设置了 \opt{kanjiskip} 或 \opt{xkanjiskip}，最后的设置会影响
% 全段。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_update_xkanjiskip:
  {
    \skip_if_eq:nnT
      { \ltjgetparameter { xkanjiskip } } { \l_@@_xkanjiskip_skip }
      {
        \skip_set:Nn \l_@@_xkanjiskip_skip { .25 \zw plus 1pt minus 1pt }
        \ltjsetparameter { xkanjiskip = \l_@@_xkanjiskip_skip }
      }
  }
%    \end{macrocode}
% 注意，此时还没有实际设置字体，所以 \cs{zw} 是 \opt{0pt}。
%    \begin{macrocode}
\skip_new:N \l_@@_xkanjiskip_skip
\skip_set:Nn \l_@@_xkanjiskip_skip { .25 \zw plus 1pt minus 1pt }
%    \end{macrocode}
% \end{macro}
%
% 在抄录环境中禁用 \opt{autospacing} 和 \opt{autoxspacing}。然而，\pkg{luatexja}
% 还是会使 JAchar 自动折行。没有看到有简单的禁用折行的办法，可能需要设置所有的
% JAchar 的 \opt{prebreakpenalty} 或 \opt{postbreakpenalty} 为 \texttt{10000}：
% \begin{verbatim}
%   \directlua
%     {
%       luatexja.isglobal = tex.globaldefs > 0 and "global" or ""
%       for i = 0x80, 0x10FFFF do
%         if luatexja.charrange.jcr_table_main[i] > 0 and
%            luatexja.charrange.jcr_table_main[i] < 218 and
%            luatexja.charrange.is_japanese_char_curlist(i) then
%           luatexja.stack.set_stack_table(luatexja.stack_table_index.PRE + i, 10000)
%         end
%       end
%     }
% \end{verbatim}
%    \begin{macrocode}
\AtBeginDocument
  {
    \ctex_appto_cmd:NnTF \verbatim@font { \CTEX@verbatim@font@hook }
      { } { \ctex_patch_failure:N \verbatim@font }
  }
\cs_new_protected_nopar:Npn \CTEX@verbatim@font@hook
  { \ltjsetparameter { autospacing = false , autoxspacing = false } }
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=ctex>
%    \end{macrocode}
%
%    \begin{macrocode}
%</luatex>
%<*pdftex|xetex|luatex>
%    \end{macrocode}
%
% \subsubsection{调整 \cs{CJKfamilydefault}}
%
% \begin{macro}[internal]{\ctex_update_default_family:}
% 在导言区结束，如果 \cs{CJKfamilydefault} 没有被更改，则在此时根据西文字体的情况
% 更新 \cs{CJKfamilydefault}。\pkg{xeCJK} 已经有这个功能，不需要再调整。
%    \begin{macrocode}
%<*pdftex|luatex>
\cs_new_protected_nopar:Npn \ctex_update_default_family:
  {
    \tl_if_eq:NNT \CJKfamilydefault \l_@@_family_default_init_tl
      {
        \group_begin:
          \cs_set_eq:NN \@@_family_default_wrap:n \exp_not:n
          \tl_gset:Nx \CJKfamilydefault
            {
              \str_case:onF { \familydefault }
                {
                  { \rmdefault } { \exp_not:N \CJKrmdefault }
                  { \sfdefault } { \exp_not:N \CJKsfdefault }
                  { \ttdefault } { \exp_not:N \CJKttdefault }
                }
                { \CJKfamilydefault }
            }
        \group_end:
      }
%    \end{macrocode}
% 使用 \LuaLaTeX{} 时，自动调整得到的 \cs{CJKfamilydefault} 可能没有定义，需要确认
% 它的存在性。使用 \pkg{CJK} 宏包时，\texttt{C19rm} 等总是有定义的，不需要确认。
%    \begin{macrocode}
%<*luatex>
    \ctex_ltj_ensure_default_family:
%</luatex>
  }
\AtEndPreamble { \ctex_update_default_family: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\l_@@_family_default_init_tl}
% 往 \cs{CJKfamilydefault} 中加入标志，用于判断它是否被更改。
%    \begin{macrocode}
\tl_new:N \l_@@_family_default_init_tl
\cs_new_eq:NN \@@_family_default_wrap:n \use:n
\tl_set:Nx \l_@@_family_default_init_tl
  {
    \exp_not:N \@@_family_default_wrap:n
      { \exp_not:o { \CJKfamilydefault } }
  }
\tl_gset_eq:NN \CJKfamilydefault \l_@@_family_default_init_tl
%</pdftex|luatex>
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{操作系统的判断}
%
% \changes{v2.0}{2014/04/16}{自动检测操作系统，载入对应的字体配置。}
%
% \begin{macro}[internal]{\ctex_detected_platform:}
% 在 \LuaTeX{} 下直接用调用 |os.name| 来判断。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_detected_platform:
%<*luatex>
  {
    \tl_gset:Nx \g_@@_fontset_tl
      {
        \ctex_lua_now_x:n
          {
            if ~ os.name == 'windows' then ~
              tex.sprint ( 'windows' )
            elseif ~ os.name == 'macosx' then ~
              tex.sprint ( 'mac' )
            else ~
              tex.sprint ( 'fandol' )
            end
          }
      }
  }
%</luatex>
%    \end{macrocode}
% \pdfTeX{} 和 \XeTeX{} 下则依据 \file{/dev/null} 和 \file{nul:} 的存在性以及
% 文件系统的大小写敏感性来判断。Mac~OS~X 的大小写敏感性在安装时是可选的。为了
% 保险起见，这里的判断很繁琐，最多要进行 4 次文件操作！
%    \begin{macrocode}
%<*xetex|pdftex>
  {
    \file_if_exist:nTF { /dev/null }
      {
        \file_if_exist:nTF { nul: }
          {
            \file_if_exist:nTF { \c_@@_engine_file_tl }
              { \ctex_if_macosx:TF { mac } { windows } }
              { \ctex_if_macosx:TF { mac } { fandol } }
          }
          { \ctex_if_macosx:TF { mac } { fandol } }
      }
      { \tl_gset:Nn \g_@@_fontset_tl { windows } }
  }
\tex_uppercase:D \exp_after:wN
  {
    \exp_after:wN \tl_const:Nn \exp_after:wN \c_@@_engine_file_tl
    \exp_after:wN { \g_file_current_name_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_if_macosx:TF}
% 以 \file{/mach_kernel} 为特征文件判断 Mac~OS~X。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_if_macosx:TF #1#2
  {
    \file_if_exist:nTF { \c_@@_macosx_file_tl }
      { \tl_gset:Nn \g_@@_fontset_tl {#1} }
      { \tl_gset:Nn \g_@@_fontset_tl {#2} }
  }
\tl_const:Nn \c_@@_macosx_file_tl { /mach_kernel }
%</xetex|pdftex>
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{\pkg{hyperref} 的支持选项}
%
% 处理各个引擎下的 PDF 中文书签问题。在 \pdfTeX{} 下使用 \texttt{GBK} 编码，
% \dvipdfmx{} 驱动可以直接用它的 \cs{special} 命令，其它模式用
% \pkg{xCJK2uni} 宏包处理。使用 \texttt{UTF-8} 编码时，\pkg{CJKutf8} 已经处理了
% 书签问题，但仍需要设置 \opt{pdfencoding} 为 \opt{unicode}，目的是在书签的
% 开头写入 BOM (|\376\377|)，提示这是 \texttt{UTF-16BE} 字节流。
%    \begin{macrocode}
%<*pdftex>
\cs_if_free:NF \hypersetup
  {
    \hypersetup { driverfallback = dvipdfmx }
    \str_if_eq:onTF { \l_@@_encoding_tl } { GBK }
      {
        \hypersetup { CJKbookmarks = true }
        \ctex_if_pdfmode:TF
          { \RequirePackage { xCJK2uni } }
          {
            \AtEndPreamble
              {
                \str_if_eq:onTF { \Hy@driver } { hdvipdfm }
                  {
                    \AtBeginShipoutFirst
                      { \special { pdf:tounicode~GBK-EUC-UCS2 } }
                  }
                  { \RequirePackage { xCJK2uni } }
              }
          }
      }
      { \hypersetup { pdfencoding = unicode } }
  }
%</pdftex>
%    \end{macrocode}
% 在 \XeTeX{} 下，\pkg{hyperref} 在处理带有非 ASCII 字符和 |\%| 的书签时有问题^^A
% \footnote{\url{http://code.google.com/p/ctex-kit/issues/detail?id=40}}。
% 事实上，\pkg{hyperref} 在驱动文件 \file{hxetex.def} 中设置了
% \cs{Hy@unicodetrue}，从而书签总是会被 \cs{HyPsd@ConvertToUnicode} 转化成
% \texttt{UTF-16BE} 编码的形式（抄录自 \cs{pdfstringdef}的定义）：
% \begin{verbatim}
%       \ifHy@unicode
%         \HyPsd@ConvertToUnicode#1%
%         \ifx\HyPsd@pdfencoding\HyPsd@pdfencoding@auto
%           \ltx@IfUndefined{StringEncodingConvertTest}{%
%           }{%
%             \EdefUnescapeString\HyPsd@temp#1%
%             \ifxetex
%               \let\HyPsd@UnescapedString\HyPsd@temp
%               \StringEncodingConvertTest\HyPsd@temp\HyPsd@temp
%                                         {utf16be}{ascii-print}{%
%                 \EdefEscapeString\HyPsd@temp\HyPsd@temp
%                 \global\let#1\HyPsd@temp
%                 \HyPsd@EscapeTeX#1%
%                 \Hy@unicodefalse
%               }{%
%                \HyPsd@ToBigChars#1%
%               }%
% \end{verbatim}
% 通过宏包选项 \opt{pdfencoding=unicode} 设置 \cs{HyPsd@pdfencoding} 为
% \opt{unicode}，可以避免随后再将书签从 \texttt{UTF-16BE} 字节流转化回正常
% 字符（其中使用的 \cs{HyPsd@ToBigChars} 没有考虑书签中含有 |\%| 的情况）。
% Heiko Oberdiek 在 \file{README} 中说明了将书签转化回正常字符的意图：避免
% XDVIPDFMX 的警告^^A
% \footnote{\url{http://project.ktug.org/dvipdfmx/mailman/dvipdfmx/2009-December/000153.html}}：
% \begin{verbatim}
%   ** WARNING ** Failed to convert input string to UTF16...
% \end{verbatim}
% \XeTeX{} 的维护者 Khaled Hosny 已经注意到了这个问题^^A
% \footnote{\url{http://tug.org/pipermail/tex-live/2013-December/034613.html}}。
% 需要注意的是，\file{hxetex.def} 重载了宏包选项 \opt{unicode}，目的是不能设置
% 它为 \opt{false}，但也导致它不会改变 \cs{HyPsd@pdfencoding}。如果
% \pkg{hyperref} 先于 \CTeX{} 被载入，那么 \opt{unicode} 选项是没有意义的。
% 因此要通过意义相同但在 \XeTeX{} 下更保险的 \opt{pdfencoding} 选项来设置。
% 为了与 \XeTeX 下的行为一致（使用 \cs{HyPsd@LoadUnicode} 载入 \file{puenc.def}），
% 在 \LuaTeX{} 下也启用这个选项。
%    \begin{macrocode}
%<*xetex|luatex>
\cs_if_exist_use:NT \hypersetup { { pdfencoding = unicode } }
%</xetex|luatex>
%    \end{macrocode}
%
% \subsubsection{\opt{fntef} 选项}
%
%    \begin{macrocode}
%<*luatex>
\msg_new:nnn { ctex } { fntef-not-available }
  { Option~`fntef'~is~not~available~in~LuaLaTeX. }
%</luatex>
\if_bool:N \l_@@_fntef_bool
%<pdftex>  \RequirePackage { CJKfntef } \normalem
%<xetex>  \RequirePackage { xeCJKfntef }
%<luatex>  \msg_warning:nn { ctex } { fntef-not-available }
  \clist_map_inline:nn
    { underdot , underline , underdblline , underwave , sout , xout }
%<*pdftex|xetex>
    { \cs_new_protected_nopar:cpx { CTEX#1 } { \exp_not:c { CJK#1 } } }
  \cs_new_protected_nopar:Npn { \CTEXfilltwosides } { \CJKfilltwosides }
  \cs_new_protected_nopar:Npn { \endCTEXfilltwosides } { \endCJKfilltwosides }
  \clist_map_inline:nn
    {
      underdotbasesep ,   underdotsep ,     underlinebasesep ,
      underlinesep ,      underdbllinesep , underdbllinebasesep ,
      underwavebasesep ,  underwavesep ,    southeight ,
      underdotcolor ,     underwavecolor ,  underlinecolor ,
      underdbllinecolor , soutcolor ,       xoutcolor
    }
    {
      \cs_new_eq:cc { CTEX#1 } { CJK#1 }
      \cs_set_nopar:cpx { CJK#1 } { \exp_not:c { CTEX#1 } }
    }
%</pdftex|xetex>
%<*luatex>
    { \cs_new_eq:cN { CTEX#1 } \use:n }
  \cs_new_eq:NN \CTEXfilltwosides \use_none:n
  \cs_new_eq:NN \endCTEXfilltwosides \prg_do_nothing:
%</luatex>
\fi:
%    \end{macrocode}
%
% \subsubsection{\cs{ccwd} 的更新}
%
% \begin{macro}[internal]{\ctex_update_ccwd:,\ccwd}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_ccwd:
%<*pdftex|xetex>
  {
    \hbox_set:Nn \l_@@_tmp_box { \CJKglue }
    \dim_set:Nn \ccwd { \box_wd:N \l_@@_tmp_box + \f@size \p@ }
  }
%</pdftex|xetex>
%<*luatex>
  { \skip_set:Nn \ccwd { \ltjgetparameter { kanjiskip } + \zw } }
%</luatex>
\dim_new:N \ccwd
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_update_ccglue:}
% 更新字间距。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_ccglue:
%<*pdftex>
  {
    \cs_set_protected_nopar:Npn \CJKglue
      { \skip_horizontal:N \l_@@_ccglue_skip }
  }
%</pdftex>
%<*xetex>
  { \xeCJKsetup { CJKglue = { \skip_horizontal:N \l_@@_ccglue_skip } } }
%</xetex>
%<*luatex>
  { \ltjsetparameter { kanjiskip = \l_@@_ccglue_skip } }
%</luatex>
\skip_new:N \l_@@_ccglue_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,pTF]{\ctex_if_ccglue_touched:}
% 检查用户是否修改过汉字间距。
%    \begin{macrocode}
\prg_new_conditional:Npnn \ctex_if_ccglue_touched: { TF }
  {
%<*pdftex|xetex>
    \if_meaning:w \CJKglue \@@_ccglue:
      \prg_return_false: \else: \prg_return_true: \fi:
%</pdftex|xetex>
%<*luatex>
    \skip_if_eq:nnTF { \l_@@_ccglue_skip } { \ltjgetparameter { kanjiskip } }
      { \prg_return_false: } { \prg_return_true: }
%</luatex>
  }
%    \end{macrocode}
% 注意下面的标记不能用 \verb"%<pdftex|xetex>"，它会导致旧版本的 \pkg{l3docstrip}
% 不能替换 \texttt{@@}。
%    \begin{macrocode}
%<*pdftex|xetex>
\ctex_at_end:n { \cs_new_eq:NN \@@_ccglue: \CJKglue }
%</pdftex|xetex>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_update_em_unit:}
% 将当前汉字的宽度保存到 \cs{ccwd} 中备用。不采用 \texttt{1 em}，因为这时的
% \texttt{1 em} 实际上来自西文字体的信息，未必等于汉字的宽度，这似乎在传统的
% \file{.tfm} 字体上表现更明显。在 \pdfTeX{} 和 \XeTeX{} 下，直接使用 |\f@size\p@|
% 作为汉字的宽度，这应该对大多数汉字字体都成立，但不适用于诸如“方正兰亭黑长”之类
% 的特殊字体。在 \XeTeX{} 可以用 \cs{fontcharwd} 来改进。而在 \pdfTeX{} 下，若使用
% \pkg{zhmetrics} 技术，所有的汉字共享同一个 \file{.tfm}，\cs{fontcharwd} 也就没有
% 意义。在 \LuaTeX{} 下，\pkg{luatexja} 总是按照 JFM 中的设置输出汉字的宽度，可以
% 直接用 \cs{zw} 作为汉字宽度。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_em_unit:
%<pdftex|xetex>  { \dim_set:Nn \ccwd { \f@size \p@ } }
%<luatex>  { \dim_set_eq:NN \ccwd \zw }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{其它}
%
% \begin{macro}[internal]{\ctex_add_to_selectfont:n,\CTEX@selectfont@hook}
% \cs{EverySelectfont} 直到文档开始时才有效。为了 \cs{ccwd} 和 \pkg{luatexja} 的
% 字体设置在导言区也可用，我们还需要在这里手工修改 \cs{selectfont}。\pkg{everysel}
% 宏包会用 \cs{CheckCommand} 来检查 \cs{selectfont} 是否为标准定义。我们修改了
% \cs{selectfont}，所以会给出一个警告。为了消除这个警告，在它检查之前，还原本来
% 定义。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_add_to_selectfont:n #1
  {
    \cs_set_protected_nopar:Npx \CTEX@selectfont@hook
      { \exp_not:o { \CTEX@selectfont@hook #1 } }
  }
\cs_new_eq:NN \CTEX@selectfont@hook \prg_do_nothing:
\cs_new_eq:Nc \@@_save_selectfont: { selectfont ~ }
\use:n
  {
    \ExplSyntaxOff
    \ctex_preto_cmd:NnTF \selectfont { \CTEX@selectfont@hook }
      {
        \tl_put_left:Nn \@EverySelectfont@Init
          { \cs_set_eq:cN { selectfont ~ } \@@_save_selectfont: }
      }
      { \ctex_patch_failure:N \selectfont }
  }
\ExplSyntaxOn
%    \end{macrocode}
% \end{macro}
%
% \cs{CJK@plane} 有定义，说明处于 \pkg{CJK} 宏包的 \cs{CJKsymbol} 之内，不必使用钩子。
%    \begin{macrocode}
%<*pdftex>
\EverySelectfont { \cs_if_exist:NF \CJK@plane { \CTEX@selectfont@hook } }
%</pdftex>
%<*xetex|luatex>
\EverySelectfont { \CTEX@selectfont@hook }
%</xetex|luatex>
%    \end{macrocode}
%
% Attribute 寄存器 \cs{ltj@curjfnt} 的初始值是 $-1$，必须把它设置为一个有效的
% \texttt{font.id}，否则编译时会直接退出。
%    \begin{macrocode}
%<*luatex>
\ctex_add_to_selectfont:n
  {
    \ctex_ltj_select_font:
    \ctex_ltj_select_alternate_font:
    \ctex_ltj_update_xkanjiskip:
  }
\tl_set:Nn \CJK@family { song } \selectfont
\tl_clear:N \CJK@family
%</luatex>
%    \end{macrocode}
%
% \begin{macro}{space}
% 在正文中设置忽略空格方式。
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
%<*pdftex|xetex>
    space .choice: ,
    space .default:n = { true } ,
    space / true  .code:n =
%<pdftex>      { \cs_set_eq:NN \CJK@ignorespaces \prg_do_nothing: } ,
%<xetex>      { \xeCJKsetup { CJKspace = true } } ,
    space / auto  .code:n =
%<pdftex>      { \cs_set_eq:NN \CJK@ignorespaces \ctex_auto_ignorespaces: } ,
%<xetex>      { \xeCJKsetup { CJKspace = false } } ,
    space / false .code:n =
%<pdftex>      { \cs_set_eq:NN \CJK@ignorespaces \tex_ignorespaces:D }
%<xetex>      { \xeCJKsetup { CJKspace = false } }
%</pdftex|xetex>
%<*luatex>
    space .code:n =
      { \msg_warning:nn { ctex } { invalid-option } }
%</luatex>
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</pdftex|xetex|luatex>
%<*class|style|ctexsize>
%    \end{macrocode}
%
% \subsection{中文字号}
%
% \changes{v2.0}{2014/03/08}{将中文字号功能提取到可以独立使用的 \pkg{ctexsize}。}
%
% \begin{macro}{\zihao}
%    \begin{macrocode}
\NewDocumentCommand \zihao { m }
  { \exp_args:Nx \ctex_zihao:n {#1} \tex_ignorespaces:D }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_zihao:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_zihao:n #1
  {
    \prop_get:NnNTF \c_@@_font_size_prop {#1} \l_@@_font_size_tl
      { \exp_after:wN \fontsize \l_@@_font_size_tl \selectfont }
      { \msg_error:nnn { ctex } { fontsize } {#1} }
  }
\msg_new:nnnn { ctex } { fontsize }
  { Undefined~Chinese~font~size~`#1'~in~command~\token_to_str:N \zihao.}
  {
    The~old~font~size~is~used~if~you~continue.\\
    The~available~font~sizes~are~listed~as~follow.\\
    \seq_use:Nnnn \c_@@_font_size_seq { ~and~ } { ,~ } { ,~and~ }.
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{定义中文字号}
%
% \changes{v2.0}{2014/03/08}{中文字号不再采用近似值。}
%
% \begin{variable}[internal]{\c_@@_font_size_prop}
% \begin{macro}[aux]{\@@_save_font_size:nn}
% 基础行距是字号的 $1.2$ 倍，采用 \hologo{eTeX} 的 scaling 运算得到的结果
% 要比简单的 |1.2\dimexpr| 精确^^A
% \footnote{\url{http://thread.gmane.org/gmane.comp.tex.latex.latex3/3190}}。
%    \begin{macrocode}
\prop_new:N \c_@@_font_size_prop
\seq_new:N \c_@@_font_size_seq
\cs_new_protected_nopar:Npn \@@_save_font_size:nn #1#2
  {
    \use:x
      {
        \prop_gput:Nnn \exp_not:N \c_@@_font_size_prop {#1}
          {
            { \dim_to_decimal:n {#2} }
            { \dim_to_decimal:n { (#2) * \c_six / \c_five } }
          }
      }
    \seq_gput_right:Nn \c_@@_font_size_seq {#1}
  }
\clist_map_inline:nn
  {
    {  8 } { 5    bp } ,
    {  7 } { 5.5  bp } ,
    { -6 } { 6.5  bp } ,
    {  6 } { 7.5  bp } ,
    { -5 } { 9    bp } ,
    {  5 } { 10.5 bp } ,
    { -4 } { 12   bp } ,
    {  4 } { 14   bp } ,
    { -3 } { 15   bp } ,
    {  3 } { 16   bp } ,
    { -2 } { 18   bp } ,
    {  2 } { 22   bp } ,
    { -1 } { 24   bp } ,
    {  1 } { 26   bp } ,
    { -0 } { 36   bp } ,
    {  0 } { 42   bp }
  }
  { \@@_save_font_size:nn #1 }
%    \end{macrocode}
% \end{macro}
% \end{variable}
%
% \subsubsection{修改默认字号大小}
%
% \begin{macro}[internal]{\ctex_set_font_size:Nnn}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_font_size:Nnn #1#2#3
  {
    \prop_get:NnNTF \c_@@_font_size_prop {#2} \l_@@_font_size_tl
      { \exp_after:wN \@@_set_font_size:nnNn \l_@@_font_size_tl #1 {#3} }
      { \msg_error:nnn { ctex } { fontsize } {#2} }
  }
\cs_new_protected:Npn \@@_set_font_size:nnNn #1#2#3#4
  { \cs_set_protected_nopar:Npn #3 { \@setfontsize #3 {#1} {#2} #4 } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\if_case:w \g_@@_font_size_flag
  \ctex_set_font_size:Nnn \normalsize { 5 }
    {
      \abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@
      \abovedisplayshortskip \z@ \@plus3\p@
      \belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@
      \belowdisplayskip \abovedisplayskip
      \let\@listi\@listI
    }
  \ctex_set_font_size:Nnn \small { -5 }
    {
      \abovedisplayskip 8.5\p@ \@plus3\p@ \@minus4\p@
      \abovedisplayshortskip \z@ \@plus2\p@
      \belowdisplayshortskip 4\p@ \@plus2\p@ \@minus2\p@
      \def\@listi{\leftmargin\leftmargini
                  \topsep 4\p@ \@plus2\p@ \@minus2\p@
                  \parsep 2\p@ \@plus\p@ \@minus\p@
                  \itemsep \parsep}
      \belowdisplayskip \abovedisplayskip
    }
  \ctex_set_font_size:Nnn \footnotesize { 6 }
    {
      \abovedisplayskip 6\p@ \@plus2\p@ \@minus4\p@
      \abovedisplayshortskip \z@ \@plus\p@
      \belowdisplayshortskip 3\p@ \@plus\p@ \@minus2\p@
      \def\@listi{\leftmargin\leftmargini
                  \topsep 3\p@ \@plus\p@ \@minus\p@
                  \parsep 2\p@ \@plus\p@ \@minus\p@
                  \itemsep \parsep}
      \belowdisplayskip \abovedisplayskip
    }
  \ctex_set_font_size:Nnn \scriptsize { -6 } { }
  \ctex_set_font_size:Nnn \tiny  {  7 } { }
  \ctex_set_font_size:Nnn \large { -4 } { }
  \ctex_set_font_size:Nnn \Large { -3 } { }
  \ctex_set_font_size:Nnn \LARGE { -2 } { }
  \ctex_set_font_size:Nnn \huge  {  2 } { }
  \ctex_set_font_size:Nnn \Huge  {  1 } { }
\or:
  \ctex_set_font_size:Nnn \normalsize { -4 }
    {
      \abovedisplayskip 12\p@ \@plus3\p@ \@minus7\p@
      \abovedisplayshortskip \z@ \@plus3\p@
      \belowdisplayshortskip 6.5\p@ \@plus3.5\p@ \@minus3\p@
      \belowdisplayskip \abovedisplayskip
      \let\@listi\@listI
    }
  \ctex_set_font_size:Nnn \small { 5 }
    {
      \abovedisplayskip 11\p@ \@plus3\p@ \@minus6\p@
      \abovedisplayshortskip \z@ \@plus3\p@
      \belowdisplayshortskip 6.5\p@ \@plus3.5\p@ \@minus3\p@
      \def\@listi{\leftmargin\leftmargini
                  \topsep 9\p@ \@plus3\p@ \@minus5\p@
                  \parsep 4.5\p@ \@plus2\p@ \@minus\p@
                  \itemsep \parsep}
      \belowdisplayskip \abovedisplayskip
    }
  \ctex_set_font_size:Nnn \footnotesize { -5 }
    {
      \abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@
      \abovedisplayshortskip \z@ \@plus3\p@
      \belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@
      \def\@listi{\leftmargin\leftmargini
                  \topsep 6\p@ \@plus2\p@ \@minus2\p@
                  \parsep 3\p@ \@plus2\p@ \@minus\p@
                  \itemsep \parsep}
      \belowdisplayskip \abovedisplayskip
    }
  \ctex_set_font_size:Nnn \scriptsize { 6 } { }
  \ctex_set_font_size:Nnn \tiny  { -6 } { }
  \ctex_set_font_size:Nnn \large { -3 } { }
  \ctex_set_font_size:Nnn \Large { -2 } { }
  \ctex_set_font_size:Nnn \LARGE {  2 } { }
  \ctex_set_font_size:Nnn \huge  { -1 } { }
  \ctex_set_font_size:Nnn \Huge  {  1 } { }
\fi:
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_declare_math_sizes:nnnn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_declare_math_sizes:nnnn #1#2#3#4
  {
    \@@_get_font_sizes:Nn \l_@@_font_size_tl { {#1} {#2} {#3} {#4} }
    \exp_after:wN \DeclareMathSizes \l_@@_font_size_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_get_font_sizes:Nn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_get_font_sizes:Nn #1#2
  {
    \tl_clear:N #1
    \tl_map_inline:nn {#2}
      {
        \prop_get:NnNTF \c_@@_font_size_prop {##1} \l_@@_tmp_tl
          { \tl_put_right:Nx #1 { { \tl_head:N \l_@@_tmp_tl } } }
          { \tl_put_right:Nx #1 { { \dim_to_decimal:n { ##1 } } } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\clist_map_inline:nn
  {
    {  8 }{  8 }{ 5pt }{ 5pt } ,
    {  7 }{  7 }{ 5pt }{ 5pt } ,
    { -6 }{ -6 }{ 5pt }{ 5pt } ,
    {  6 }{  6 }{ 5pt }{ 5pt } ,
    { -5 }{ -5 }{ 6pt }{ 5pt } ,
    {  5 }{  5 }{ 7pt }{ 5pt } ,
    { -4 }{ -4 }{ 8pt }{ 6pt } ,
    {  4 }{  4 }{  5 }{  6 } ,
    { -3 }{ -3 }{ -4 }{ -5 } ,
    {  3 }{  3 }{  4 }{  5 } ,
    { -2 }{ -2 }{ -3 }{ -4 } ,
    {  2 }{  2 }{  3 }{  4 } ,
    { -1 }{ -1 }{ -2 }{ -3 } ,
    {  1 }{  1 }{  2 }{  3 } ,
    { -0 }{ -0 }{ -1 }{ -2 } ,
    {  0 }{  0 }{  1 }{  2 }
  }
  { \ctex_declare_math_sizes:nnnn #1 }
%    \end{macrocode}
%
%    \begin{macrocode}
%<ctexsize>\normalsize
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|style|ctexsize>
%<*class|style>
%    \end{macrocode}
%
% \subsubsection{字距与缩进}
%
% \begin{macro}{autoindent}
% |autoindent| 也是可以用在正文中的选项，意义与宏包选项 |option/autoindent| 相同。
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
    autoindent .choice: ,
    autoindent .default:n = { true } ,
    autoindent / true  .code:n =
      {
        \bool_set_true:N \l_@@_autoindent_bool
        \ctex_update_parindent:
      } ,
    autoindent / false .code:n =
      { \bool_set_false:N \l_@@_autoindent_bool }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEXsetfont}
% 无论字体大小是否变化都更新相关信息。
%    \begin{macrocode}
\NewDocumentCommand \CTEXsetfont { }
  { \cs_if_free:NTF \size@update { \ctex_update_size: } { \selectfont } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_update_size:}
% 在字号变化时更新 \cs{ccwd}、\cs{parindent} 和汉字间距。字距为零则恢复正常设置。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_size:
  {
    \tl_if_eq:NNTF \l_@@_ziju_tl \c_@@_zero_tl
      {
        \ctex_update_stretch:
        \ctex_update_parindent:
      }
      { \ctex_update_ziju: }
  }
\tl_const:Nx \c_@@_zero_tl { \fp_use:N \c_zero_fp }
\tl_new:N \l_@@_ziju_tl
\tl_set_eq:NN \l_@@_ziju_tl \c_@@_zero_tl
%    \end{macrocode}
% 在 \cs{selectfont} 中，若 \cs{size@update} 为 \cs{relax}，说明字体大小没有变化，
% 我们也就不用更新相关参数。
%    \begin{macrocode}
\ctex_add_to_selectfont:n
  { \cs_if_free:NF \size@update { \ctex_update_size: } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{linestretch}
% 若行宽不是汉字宽度的整数倍，自然要求伸展它们之间的差。这里设置的是在此基础上的
% 额外伸展量。初始化为一个汉字的宽度。若设置为 \cs{maxdimen}，则禁用此功能。
% 参数的默认单位是汉字的宽度 \cs{ccwd}。
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
    linestretch .code:n =
      {
        \dim_compare:nNnTF
          { \ctex_default_pt:n {#1} } = { \ctex_default_pt:n { #1 in } }
          { \tl_set:Nn \l_@@_line_stretch_tl {#1} }
          { \tl_set:Nn \l_@@_line_stretch_tl { #1 \ccwd } }
        \CTEXsetfont
      } ,
    linestretch .value_required:
  }
\tl_new:N \l_@@_line_stretch_tl
\tl_set:Nn \l_@@_line_stretch_tl { \ccwd }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_update_stretch:}
% 首先计算一行上汉字的字数，\cs{CJKglue} 相当于将 \cs{linewidth} 与汉字总宽度之差
% 均匀地填充到汉字之间。\hologo{eTeX} 的除法是四舍五入，而我们这里应该用截断。由于
% 没有可展性的要求，直接用原语 \cs{tex_divide:D} 要比 \cs{int_div_truncate:nn}
% 快一些。下面的算法还兼顾到了 \cs{linewidth} 不为汉字字宽的整数倍的情况。
% 若用户禁用 \opt{linestretch} 并且修改过 \cs{CJKglue}，则只更新
% \cs{ccwd}，否则设置伸展量为 $0.08$ 倍 \cs{baselineskip}。注意 \pkg{everysel} 的
% 钩子位于 \cs{size@update} 之前，\cs{baselineskip} 还未更新，不能直接使用它。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_stretch:
  {
    \ctex_update_em_unit:
    \dim_set:Nn \l_@@_tmp_dim { \l_@@_line_stretch_tl }
    \dim_compare:nNnTF \l_@@_tmp_dim = \c_max_dim
      {
        \ctex_if_ccglue_touched:TF
          { \ctex_update_ccwd: }
          {
            \dim_set:Nn \l_@@_tmp_dim
              { \baselinestretch \etex_glueexpr:D \f@baselineskip \scan_stop: }
            \skip_set:Nn \l_@@_ccglue_skip
              { \c_zero_dim plus .08 \l_@@_tmp_dim }
            \ctex_update_ccglue:
          }
      }
      {
        \int_set:Nn \l_@@_tmp_int
          { \etex_dimexpr:D \linewidth - \ccwd - \l_@@_tmp_dim \scan_stop: }
        \tex_divide:D \l_@@_tmp_int \ccwd
        \int_compare:nNnTF \l_@@_tmp_int > \c_zero
          {
            \skip_set:Nn \l_@@_ccglue_skip
              {
                \c_zero_dim plus \dim_eval:n
                  {
                    ( \linewidth - \ccwd - \l_@@_tmp_int \ccwd ) /
                    \l_@@_tmp_int
                  }
              }
          }
          { \skip_zero:N \l_@@_ccglue_skip }
        \ctex_update_ccglue:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_update_parindent:}
% 更新段落首行缩进。此函数在字号变化时调用。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_parindent:
  {
    \bool_if:NT \l_@@_autoindent_bool
      {
        \dim_compare:nNnF \parindent = \c_zero_dim
          { \dim_set:Nn \parindent { 2 \ccwd } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ziju}
% 若参数为 $0$，则恢复正常间距。
%    \begin{macrocode}
\NewDocumentCommand \ziju { m }
  { \exp_args:Nx \ctex_ziju:n {#1} \tex_ignorespaces:D }
\cs_new_protected_nopar:Npn \ctex_ziju:n #1
  {
    \tl_set:Nx \l_@@_ziju_tl { \fp_eval:n {#1} }
    \CTEXsetfont
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_update_ziju:}
% 更新字距。若字距不大于 $-1$，即 \cs{ccwd} 为非正值，则不计算伸缩值。
% 否则，首先假定汉字的宽度为正常宽度加上字距，看一行上能正常放下多少个汉字。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_update_ziju:
  {
    \ctex_update_em_unit:
    \dim_set:Nn \l_@@_ziju_dim { \l_@@_ziju_tl \ccwd }
    \dim_add:Nn \ccwd { \l_@@_ziju_dim }
    \dim_compare:nNnTF \ccwd > \c_zero_dim
%    \end{macrocode}
% 伸展量保证行内的剩余空白能够被均匀地填充到汉字之间，收缩的最大限度是让当前行
% 还能够再挤下一个汉字并且不会出现负间距。由 \TeX{} 决定伸展还是收缩。
%    \begin{macrocode}
      {
        \dim_set:Nn \l_@@_tmp_dim
          { \linewidth - \ccwd + \l_@@_ziju_dim }
        \int_set:Nn \l_@@_tmp_int { \l_@@_tmp_dim }
        \tex_divide:D \l_@@_tmp_int \ccwd
        \dim_sub:Nn \l_@@_tmp_dim { \l_@@_tmp_int \ccwd }
%    \end{macrocode}
% 由于 \cs{parindent} 是一个固定值，并不参与伸缩，容易导致第一行出现坏盒子。
% 我们在这里将字数减去 $2$，以此放大伸缩值。
%    \begin{macrocode}
        \dim_compare:nNnF \parindent = \c_zero_dim
          {
            \int_compare:nNnF \l_@@_tmp_int < \c_three
              { \int_sub:Nn \l_@@_tmp_int { \c_two } }
          }
        \skip_set:Nn \l_@@_ccglue_skip
          {
            \l_@@_ziju_dim
            plus  \dim_eval:n { \l_@@_tmp_dim / \l_@@_tmp_int }
            minus \dim_min:nn { \dim_abs:n { \l_@@_ziju_dim } }
              { ( \ccwd - \l_@@_tmp_dim ) / ( \l_@@_tmp_int + \c_one ) }
          }
      }
      { \skip_set:Nn \l_@@_ccglue_skip { \l_@@_ziju_dim } }
    \ctex_update_ccglue:
%    \end{macrocode}
% 字距设置得比较大时，为了尽量保证段首缩进能够与下一行对齐，应该需要相应地加上
% 或者减去伸缩值。但是这里并不清楚 \TeX{} 是伸展还是收缩，之前以“当前行是否还
% 放得下一个汉字”为标准加上或减去伸缩值的做法也未必与实际结果一致，所以只好还
% 是设置为 |2\ccwd|。
%    \begin{macrocode}
    \ctex_update_parindent:
  }
\dim_new:N \l_@@_ziju_dim
%    \end{macrocode}
% \end{macro}
%
% 更新行距。
%    \begin{macrocode}
\linespread { \fp_use:N \l_@@_line_spread_fp }
%    \end{macrocode}
%
% 激活默认字体大小，更新 \cs{parindent} 和 \cs{CJKglue}。
%    \begin{macrocode}
\normalsize
%    \end{macrocode}
%
% \changes{v2.0}{2014/04/23}{调整 \cs{footnotesep} 的大小，以适合行距的变化。}
%
% \begin{variable}[internal]{\footnotesep}
% 由于我们加宽了行距，导致脚注的间距与行距不协调，需要调整 \cs{footnotesep}。标准
% 文档类对 \cs{footnotesep} 的设置是，字体大小为 \cs{footnotesize} 时 \cs{strutbox}
% 的高度（默认值是 |.7\baselineskip|）。我们沿用这个设置方法，只需要更新具体的大小。
%    \begin{macrocode}
\group_begin: \footnotesize \exp_args:NNNo \group_end:
\dim_set:Nn \footnotesep { \dim_use:N \box_ht:N \strutbox }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\CTEXindent,\CTEXnoindent}
% 过时命令。
%    \begin{macrocode}
\NewDocumentCommand \CTEXindent { }
  { \ctex_update_ccwd: \dim_set:Nn \parindent { 2 \ccwd } }
\NewDocumentCommand \CTEXnoindent { }
  { \dim_zero:N \parindent }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\bool_if:NT \l_@@_indent_bool
  { \RequirePackage { indentfirst } }
%    \end{macrocode}
%
% \subsection{中文数字与日期}
%
%    \begin{macrocode}
\PassOptionsToPackage { encoding = \l_@@_encoding_tl } { zhnumber }
\RequirePackage { zhnumber }
%    \end{macrocode}
%
% \begin{macro}{\chinese}
%    \begin{macrocode}
\cs_new_eq:NN \chinese \zhnum
\cs_new_eq:NN \Chinese \chinese
\cs_new_eq:NN \CTEXcounter \use_none:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEXnumber,\CTEXdigits}
%    \begin{macrocode}
\NewDocumentCommand \CTEXnumber { m m }
  { \protected@edef #1 { \zhnumber {#2} } }
\NewDocumentCommand \CTEXdigits { m m }
  { \protected@edef #1 { \zhdigits {#2} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{today}
%    \begin{macrocode}
\cs_set_eq:NN \CTEX@todayold \today
\keys_define:nn { ctex }
  {
    today .choice: ,
    today / old     .code:n =
      { \cs_set_eq:NN \today \CTEX@todayold } ,
    today / small   .code:n =
      {
        \cs_set_eq:NN \today \zhtoday
        \zhnumsetup { time = Arabic }
      } ,
    today / big     .code:n =
      {
        \cs_set_eq:NN \today \zhtoday
        \zhnumsetup { time = Chinese }
      } ,
    today / unknown .code:n =
      { \msg_error:nnx { ctex } { today-undef } {#1} }
  }
\msg_new:nnnn { ctex } { today-undef }
  { Today~format~`#1'~is~undefined. }
  { Available~today~formats~are~`old',~`small',~and~`big'. }
\bool_if:NT \l_@@_caption_bool
  { \keys_set:nn { ctex } { today = small } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{其它中文标题定义}
%
% \changes{v2.0}{2014/03/08}{将标题汉化功能加入 \pkg{ctex.sty}。}
%
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
    contentsname   .tl_set:N = \contentsname ,
    listfigurename .tl_set:N = \listfigurename ,
    listtablename  .tl_set:N = \listtablename ,
    figurename     .tl_set:N = \figurename ,
    tablename      .tl_set:N = \tablename ,
    abstractname   .tl_set:N = \abstractname ,
    indexname      .tl_set:N = \indexname ,
    appendixname   .tl_set:N = \appendixname ,
%<article>    bibname        .tl_set:N = \refname
%<book|report>    bibname        .tl_set:N = \bibname
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%<*style>
\msg_new:nnn { ctex } { ctexbibname }
  {
    Neither~`\token_to_str:N \bibname'~nor~`\token_to_str:N \refname'~can~be~found.\\
    The~key~`bibname'~will~set~`\token_to_str:N \ctexbibname'~to~the~given~value.
  }
\tl_if_exist:NTF \bibname
  { \keys_define:nn { ctex } { bibname .tl_set:N = \bibname } }
  {
    \tl_if_exist:NTF \refname
      { \keys_define:nn { ctex } { bibname .tl_set:N = \refname } }
      {
        \msg_warning:nn { ctex } { ctexbibname }
        \keys_define:nn { ctex } { bibname .tl_set:N = \ctexbibname }
      }
  }
%</style>
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|style>
%<*class|heading>
%    \end{macrocode}
%
% \subsection{中文化的标题结构}
%
% \subsubsection{定义标题格式选项}
%
% \begin{variable}[internal]{\c_@@_headings_seq}
%    \begin{macrocode}
\seq_new:N \c_@@_headings_seq
\seq_gset_from_clist:Nn \c_@@_headings_seq
  {
%<article>    part , section , subsection , subsubsection ,
%<book|report>    part , chapter , section , subsection , subsubsection ,
    paragraph , subparagraph
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[internal]{\@@_initial_heading:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_initial_heading:n #1
  {
    \tl_new:c { CTEX@pre#1 }
    \tl_new:c { CTEX@post#1 }
    \tl_const:cx { CTEXthe#1 }
      {
        \exp_not:c { CTEX@pre#1 }
        \exp_not:c { CTEX@the#1 }
        \exp_not:c { CTEX@post#1 }
      }
    \tl_const:cx { CTEX@#1name }
      {
        \exp_not:c { CTEX@#1@nameformat }
        \exp_not:c { CTEX@pre#1 }
        \exp_not:N \tl_if_empty:NTF \exp_not:c { CTEX@#1@numberformat }
          { \exp_not:c { CTEX@the#1 } }
          {
            \group_begin:
              \exp_not:c { CTEX@#1@numberformat }
              \exp_not:c { CTEX@the#1 }
            \group_end:
          }
        \exp_not:c { CTEX@post#1 }
        \exp_not:c { CTEX@#1@aftername }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_def_heading_keys:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_def_heading_keys:n #1
  {
    \tl_put_right:Nx \l_@@_tmp_tl
      {
        #1                 .meta:nn = { ctex / #1 } { ####1 } ,
        #1 / name           .code:n =
          { \ctex_assign_heading_name:nn {#1} { ####1 } } ,
        #1 / number       .tl_set:N = \exp_not:c { CTEX@the#1 } ,
        #1 / format       .tl_set:N = \exp_not:c { CTEX@#1@format } ,
        #1 / nameformat   .tl_set:N = \exp_not:c { CTEX@#1@nameformat } ,
        #1 / numberformat .tl_set:N = \exp_not:c { CTEX@#1@numberformat } ,
        #1 / aftername    .tl_set:N = \exp_not:c { CTEX@#1@aftername } ,
        #1 / titleformat  .tl_set:N = \exp_not:c { CTEX@#1@titleformat } ,
        #1 / beforeskip   .tl_set:N = \exp_not:c { CTEX@#1@beforeskip } ,
        #1 / afterskip    .tl_set:N = \exp_not:c { CTEX@#1@afterskip} ,
        #1 / indent       .tl_set:N = \exp_not:c { CTEX@#1@indent } ,
        #1 / format+        .code:n =
          { \tl_put_right:Nn \exp_not:c { CTEX@#1@format } { ####1 } } ,
        #1 / nameformat+    .code:n =
          { \tl_put_right:Nn \exp_not:c { CTEX@#1@nameformat } { ####1 } } ,
        #1 / numberformat+  .code:n =
          { \tl_put_right:Nn \exp_not:c { CTEX@#1@numberformat } { ####1 } } ,
        #1 / aftername+     .code:n =
          { \tl_put_right:Nn \exp_not:c { CTEX@#1@aftername } { ####1 } } ,
        #1 / titleformat+   .code:n =
          { \tl_put_right:Nn \exp_not:c { CTEX@#1@titleformat } { ####1 } } ,
        #1 / beforeskip  .initial:n = \c_zero_skip ,
        #1 / afterskip   .initial:n = \c_zero_skip ,
        #1 / indent      .initial:n = \c_zero_dim ,
        #1 / beforeskip  .value_required: ,
        #1 / afterskip   .value_required: ,
        #1 / indent      .value_required: ,
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_assign_heading_name:nn,\@@_assign_heading_name:nnn}
% \opt{name} 的值是一个至多两个元素的逗号分隔列表。由于 \LTXIII{} 的
% \texttt{clist} 总是会自动忽略空元素，所以设置 |name={,章}| 后，第一个元素将会
% 是“章”，必须用空的分组保护空元素：|name={{},章}|，这在使用中有些许不便。我们
% 可以改用 \texttt{seq} 或者手写函数解析参数来加以改进。为实现的简单起见，这里用
% 了 \pkg{xparse} 的 \cs{SplitArgument}，它带有参数的长度检查。
%    \begin{macrocode}
\NewDocumentCommand \ctex_assign_heading_name:nn
  { m > { \SplitArgument { \c_one } { , } } +m }
  { \@@_assign_heading_name:nnn {#1} #2 }
\cs_new_protected:Npn \@@_assign_heading_name:nnn #1#2#3
  {
    \tl_set:cn { CTEX@pre#1 } {#2}
    \IfNoValueTF {#3}
      { \tl_clear:c { CTEX@post#1 } }
      { \tl_set:cn { CTEX@post#1 } {#3} }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\tl_clear:N \l_@@_tmp_tl
\seq_map_inline:Nn \c_@@_headings_seq
  {
    \@@_initial_heading:n {#1}
    \@@_def_heading_keys:n {#1}
  }
\use:x { \keys_define:nn { ctex } { \exp_not:o { \l_@@_tmp_tl } } }
\tl_clear:N \l_@@_tmp_tl
%    \end{macrocode}
%
% \changes{v2.0}{2014/03/21}{标题设置新增 \opt{pagestyle} 选项。}
%
% \begin{macro}{pagestyle}
% 只在 \cls{ctexbook} 和 \cls{ctexrep} 下有定义。
%    \begin{macrocode}
%<*book|report>
\keys_define:nn { ctex }
  {
    part    / pagestyle .tl_set:N = \CTEX@part@pagestyle ,
    chapter / pagestyle .tl_set:N = \CTEX@chapter@pagestyle
  }
%</book|report>
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{标准标题命令的修改}
%
% \paragraph{part 的标题}
%
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
% \begin{macro}[internal]{\part}
%    \begin{macrocode}
%<*article>
\renewcommand\part{%
   \if@noskipsec \leavevmode \fi
   \par
%  \addvspace{4ex}%
   \@tempskipa \CTEX@part@beforeskip \relax
   \ifdim \@tempskipa <\z@
     \@tempskipa -\@tempskipa \@afterindentfalse
   \else
     \@afterindenttrue
   \fi
   \addvspace{\@tempskipa}%
   \secdef\@part\@spart}
%</article>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@part}
%    \begin{macrocode}
%<*article>
\def\@part[#1]#2{%
  \ifnum \c@secnumdepth >\m@ne
    \refstepcounter{part}%
%   \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
    \addcontentsline{toc}{part}{\CTEXthepart\hspace{1em}#1}%
  \else
    \addcontentsline{toc}{part}{#1}%
  \fi
  {\interlinepenalty \@M
%  \normalfont \parindent \z@ \raggedright
   \normalfont \parindent \CTEX@part@indent \CTEX@part@format
   \ifnum \c@secnumdepth >\m@ne
%    \Large\bfseries\partname\nobreakspace\thepart\par\nobreak
     \CTEX@partname
   \fi
%  \huge\bfseries #2%
   \CTEX@part@titleformat{#2}%
   \markboth{}{}\par}%
  \nobreak
% \vskip 3ex
  \vskip \CTEX@part@afterskip
  \@afterheading}
%</article>
%    \end{macrocode}
%
% 标准文档类是在 \cs{part} 和 \cs{chapter} 定义的最开始设置 \cs{thispagestyle}，
% 我们这里的修改出现在它之后，可以覆盖之前的设置。
%    \begin{macrocode}
%<*book|report>
\def\@part[#1]#2{%
  \thispagestyle{\CTEX@part@pagestyle}%
  \ifnum \c@secnumdepth >-2\relax
    \refstepcounter{part}%
%   \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
    \addcontentsline{toc}{part}{\CTEXthepart\hspace{1em}#1}%
  \else
    \addcontentsline{toc}{part}{#1}%
  \fi
  \markboth{}{}%
  {\interlinepenalty \@M
%  \normalfont \centering
   \normalfont \CTEX@part@format
   \ifnum \c@secnumdepth >-2\relax
%    \huge\bfseries\partname\nobreakspace\thepart\par\vskip 20\p@
     \CTEX@partname
   \fi
%  \Huge\bfseries #2\par}%
   \CTEX@part@titleformat{#2}\par}%
  \@endpart}
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@spart}
%    \begin{macrocode}
%<*article>
\def\@spart#1{%
    {\interlinepenalty \@M
%    \normalfont \parindent \z@ \raggedright
     \normalfont \parindent \CTEX@part@indent \CTEX@part@format
%    \huge \bfseries #1\par}%
     \CTEX@part@titleformat{#1}\par}%
     \nobreak
%    \vskip 3ex
     \vskip \CTEX@part@afterskip
     \@afterheading}
%</article>
%<*book|report>
\def\@spart#1{%
    {\interlinepenalty \@M
%    \normalfont \centering
     \normalfont \CTEX@part@format
%    \Huge \bfseries #1\par}%
     \CTEX@part@titleformat{#1}\par}%
    \@endpart}
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \paragraph{chapter 的标题}
%
%    \begin{macrocode}
%<*book|report>
%    \end{macrocode}
%
% \begin{macro}[internal]{\@chapter}
%    \begin{macrocode}
\def\@chapter[#1]#2{%
  \ifnum \c@secnumdepth >\m@ne
%<book>    \if@mainmatter
      \refstepcounter{chapter}%
%     \typeout{\@chapapp\space\thechapter.}%
      \typeout{\CTEXthechapter}%
      \addcontentsline{toc}{chapter}
%       {\protect\numberline{\thechapter}#1}%
        {\protect\numberline{\CTEXthechapter\hspace{0.3em}}#1}%
%<book>    \else
%<book>      \addcontentsline{toc}{chapter}{#1}%
%<book>    \fi
  \else
    \addcontentsline{toc}{chapter}{#1}%
  \fi
  \chaptermark{#1}%
  \addtocontents{lof}{\protect\addvspace{10\p@}}%
  \addtocontents{lot}{\protect\addvspace{10\p@}}%
  \if@twocolumn
    \@topnewpage[\@makechapterhead{#2}]%
  \else
    \@makechapterhead{#2}%
  \@afterheading
  \fi}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@makechapterhead}
%    \begin{macrocode}
\def\@makechapterhead#1{%
  \thispagestyle{\CTEX@chapter@pagestyle}%
% \vspace*{50\p@}%
  \@tempskipa \CTEX@chapter@beforeskip \relax
  \ifdim \@tempskipa <\z@
    \@tempskipa -\@tempskipa \@afterindentfalse
  \else
    \@afterindenttrue
  \fi
  \vspace*{\@tempskipa}%
% {\normalfont \parindent \z@ \raggedright
  {\normalfont \parindent \CTEX@chapter@indent \CTEX@chapter@format
   \ifnum \c@secnumdepth >\m@ne
%<book>     \if@mainmatter
%      \huge\bfseries\@chapapp\space\thechapter\par\nobreak\vskip 20\p@
       \CTEX@chaptername
%<book>     \fi
   \fi
   \interlinepenalty\@M
%  \Huge \bfseries #1\par\nobreak
   \CTEX@chapter@titleformat{#1}\par\nobreak
%  \vskip 40\p@
   \vskip \CTEX@chapter@afterskip
  }}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@makeschapterhead}
%    \begin{macrocode}
\def\@makeschapterhead#1{%
  \thispagestyle{\CTEX@chapter@pagestyle}%
% \vspace*{50\p@}%
  \@tempskipa \CTEX@chapter@beforeskip \relax
  \ifdim \@tempskipa <\z@
    \@tempskipa -\@tempskipa \@afterindentfalse
  \else
    \@afterindenttrue
  \fi
  \vspace*{\@tempskipa}%
% {\normalfont \parindent \z@ \raggedright
  {\normalfont \parindent \CTEX@chapter@indent \CTEX@chapter@format
   \interlinepenalty\@M
%  \Huge \bfseries  #1\par\nobreak
   \CTEX@chapter@titleformat{#1}\par\nobreak
%  \vskip 40\p@
   \vskip \CTEX@chapter@afterskip
  }}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</book|report>
%    \end{macrocode}
%
% \paragraph{section 类的标题}
%
% \begin{macro}[internal]{\@seccntformat}
%    \begin{macrocode}
\def\@seccntformat#1{%
  \@ifundefined{CTEX@#1name}%
    {\csname the#1\endcsname\quad}%
    {\csname CTEX@#1name\endcsname}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@sect}
%    \begin{macrocode}
\def\@sect#1#2#3#4#5#6[#7]#8{%
  \ifnum #2>\c@secnumdepth
    \let\@svsec\@empty
  \else
    \refstepcounter{#1}%
    \protected@edef\@svsec{\@seccntformat{#1}\relax}%
  \fi
  \@tempskipa #5\relax
  \ifdim \@tempskipa>\z@
    \begingroup
      #6{%
        \@hangfrom{\hskip #3\relax\@svsec}%
%       \interlinepenalty \@M #8\@@par}%
        \interlinepenalty \@M
        \csname CTEX@#1@titleformat\endcsname{#8}\@@par}%
    \endgroup
    \csname #1mark\endcsname{#7}%
    \addcontentsline{toc}{#1}{%
      \ifnum #2>\c@secnumdepth \else
%       \protect\numberline{\csname the#1\endcsname}%
        \protect\numberline{\@ifundefined{CTEXthe#1}%
                              {\csname the#1\endcsname}%
                              {\csname CTEXthe#1\endcsname}}%
      \fi
      #7}%
  \else
    \def\@svsechd{%
    #6{\hskip #3\relax
%     \@svsec #8}%
      \@svsec \csname CTEX@#1@titleformat\endcsname{#8}}%
    \csname #1mark\endcsname{#7}%
    \addcontentsline{toc}{#1}{%
      \ifnum #2>\c@secnumdepth \else
%       \protect\numberline{\csname the#1\endcsname}%
        \protect\numberline{\@ifundefined{CTEXthe#1}%
                              {\csname the#1\endcsname}%
                              {\csname CTEXthe#1\endcsname}}%
      \fi
      #7}}%
  \fi
  \@xsect{#5}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@ssect}
% \tn{@ssect} 并没有参数给出当前标题的名字，扩展它的参数会与 \pkg{hyperref} 冲突。
% 它的第二个参数是 BEFORESKIP（\tn{@startsection} 的第四个参数），在定义中并没有
% 被用到，应该可以用它来传递名字。我们这里通过函数 \tn{CTEX@titleformat@n} 来传递，
% 它将在 |#4| 中被重定义为相应的 \opt{titleformat}。
%    \begin{macrocode}
\def\@ssect#1#2#3#4#5{%
  \@tempskipa #3\relax
  \ifdim \@tempskipa>\z@
    \begingroup
      #4{%
        \@hangfrom{\hskip #1}%
%         \interlinepenalty \@M #5\@@par}%
          \interlinepenalty \@M
          \CTEX@titleformat@n{#5}\@@par}%
    \endgroup
  \else
%   \def\@svsechd{#4{\hskip #1\relax #5}}%
    \def\@svsechd{#4{\hskip #1\relax \CTEX@titleformat@n{#5}}}%
  \fi
  \@xsect{#3}}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%<@@=ctex>
%    \end{macrocode}
%
% \begin{macro}[internal]{\CTEX@set@titleformat@n, \CTEX@titleformat@n}
% 在 \tn{@startsection} 中设置 \tn{CTEX@titleformat@n} 为相应函数。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \CTEX@set@titleformat@n #1
  { \cs_set_eq:Nc \CTEX@titleformat@n { CTEX@#1@titleformat } }
\cs_new_eq:NN \CTEX@titleformat@n \use:n
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\int_zero:N \l_@@_tmp_int
\clist_map_inline:nn
  { section , subsection , subsubsection , paragraph , subparagraph }
  {
    \int_incr:N \l_@@_tmp_int
    \cs_gset_protected_nopar:cpx  {#1}
      {
        \exp_not:N \@startsection {#1}
          { \int_use:N \l_@@_tmp_int }
          { \exp_not:c { CTEX@#1@indent } }
          { \exp_not:c { CTEX@#1@beforeskip } }
          { \exp_not:c { CTEX@#1@afterskip } }
          {
            \CTEX@set@titleformat@n {#1}
            \exp_not:N \normalfont \exp_not:c { CTEX@#1@format }
          }
      }
  }
%    \end{macrocode}
%
%
% \paragraph{附录标题}
%
%    \begin{macrocode}
\tl_new:N \CTEX@preappendix
\tl_new:N \CTEX@postappendix
\keys_define:nn { ctex }
  { appendix .meta:nn = { ctex / appendix } {#1} }
\keys_define:nn { ctex / appendix }
  {
    name      .code:n = { \ctex_assign_heading_name:nn { appendix } {#1} } ,
    name   .initial:n = { \appendixname \space } ,
    number  .tl_set:N = \CTEX@appendixnumber ,
%<article>    number .initial:n = { \@Alph \c@section }
%<book|report>    number .initial:n = { \@Alph \c@chapter }
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\appendix}
%    \begin{macrocode}
\cs_new_eq:NN \CTEX@save@appendix \appendix
\cs_gset_protected_nopar:Npn \appendix
  {
    \CTEX@save@appendix
%<*article>
    \gdef \CTEX@presection { \CTEX@preappendix }
    \gdef \CTEX@thesection { \CTEX@appendixnumber }
    \gdef \CTEX@postsection { \CTEX@postappendix }
%</article>
%<*book|report>
    \gdef \CTEX@prechapter { \CTEX@preappendix }
    \gdef \CTEX@thechapter { \CTEX@appendixnumber }
    \gdef \CTEX@postchapter { \CTEX@postappendix }
%</book|report>
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{目录标签的宽度}
%
% \begin{macro}[internal]{\numberline}
%   \begin{macrocode}
\cs_new_protected:Npn \CTEX@toc@width@n #1
  {
    \hbox_set:Nn \l_@@_tmp_box {#1}
    \dim_set:Nn \@tempdima
      {
        \dim_max:nn { \@tempdima }
          { \box_wd:N \l_@@_tmp_box + \f@size \p@ / \c_two }
      }
  }
\group_begin:
\char_set_catcode_other:N \#
\use:n
  {
    \group_end:
    \ExplSyntaxOff
    \ctex_preto_cmd:NnTF \numberline { \CTEX@toc@width@n {#1} } { }
      { \ctex_patch_failure:N \numberline }
    \ExplSyntaxOn
    \AtBeginDocument
      {
        \@ifpackageloaded { tocloft }
          {
            \ctex_preto_cmd:NnTF \numberline { \CTEX@toc@width@n {#1} } { }
              { \ctex_patch_failure:N \numberline }
          } { }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{页眉信息的修改}
%
% \begin{macro}[internal]{\ps@headings}
%    \begin{macrocode}
%<*article>
\ctex_patch_cmd:Nnn \ps@headings { \thesection } { \CTEXthesection }
\if@twoside
  \ctex_patch_cmd:Nnn \ps@headings { \thesubsection } { \CTEXthesubsection }
\fi:
%</article>
%<*book|report>
\ctex_patch_cmd:Nnn \ps@headings
  { \@chapapp\ \thechapter.~\ } { \CTEXthechapter \quad }
\if@twoside
  \ctex_patch_cmd:Nnn \ps@headings { \thesection.~\ } { \CTEXthesection \quad }
\fi:
%</book|report>
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\pagestyle { headings }
%    \end{macrocode}
%
%    \begin{macrocode}
\bool_if:NT \l_@@_fancyhdr_bool
  { \RequirePackage { fancyhdr } }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ps@fancy}
%    \begin{macrocode}
\if_cs_exist:N \ps@fancy
%<*article>
  \ctex_patch_cmd:Nnn \ps@fancy
    { \thesection \hskip 1em \relax } { \CTEXthesection \quad }
  \ctex_patch_cmd:Nnn \ps@fancy
    { \thesubsection \hskip 1em \relax } { \CTEXthesubsection \quad }
%</article>
%<*book|report>
  \ctex_patch_cmd:Nnn \ps@fancy { \@chapapp\ \thechapter.~\ }
%<book>    { \if@mainmatter \CTEXthechapter \quad \fi }
%<report>    { \CTEXthechapter \quad }
  \ctex_patch_cmd:Nnn \ps@fancy { \thesection.~\ } { \CTEXthesection \quad }
%</book|report>
\fi:
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{标签引用数字的汉化}
%
% \begin{macro}[internal]{\refstepcounter}
% 对标题进行引用时，设置标签为通过 \opt{number} 选项设置的形式。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \CTEX@setcurrentlabel@n #1
  {
    \protected@edef \@currentlabel
      {
        \cs_if_exist:cTF { CTEX@the#1 }
          { \exp_args:cc { p@#1 } { CTEX@the#1 } }
          { \exp_not:o { \@currentlabel } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_varioref_hook:}
% 关于标签引用的宏包可能会修改 \cs{refstepcounter}。其中 \pkg{cleveref} 和
% \pkg{hyperref} 宏包都会保存之前的定义，并且它们都要求尽可能晚的被载入，所以
% 对我们上述的修改影响不大。需要注意的是 \pkg{varioref} 宏包，如果它在
% \CTeX{} 之后被载入，我们之前的修改将会被覆盖。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_varioref_hook:
  {
    \seq_map_inline:Nn \c_@@_headings_seq
      { \ctex_fix_varioref_label:n { ##1 } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_fix_varioref_label:n}
% \pkg{varioref} 宏包的 \cs{labelformat} 实际上是定义一个以 |\the<#1>| 为参数的宏
% |\p@<#1>|。\LaTeX{} 在定义计数器 |<#1>| 时，都会将 |\p@<#1>| 初始化为 \cs{@empty}。
% 如果这个宏非空，说明用户自定义了标签格式，我们就不再修改。这里不能使用
% \cs{exp_args:Nnc}，因为 \texttt{c} 这种展开格式不会将参数放在花括号内。而
% \cs{labelformat} 的定义是
% \begin{verbatim}
%   \def\labelformat#1{\expandafter\def\csname p@#1\endcsname##1}
% \end{verbatim}
% 它的第二个参数必须放在花括号内，否则将会被作为宏的定界符号。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_fix_varioref_label:n #1
  {
    \tl_if_empty:cT { p@#1 }
      { \exp_args:Nno \labelformat {#1} { \cs:w CTEX@the#1 \cs_end: } }
  }
%    \end{macrocode}
% \end{macro}
%
% 如果 \pkg{varioref} 已经被载入，则使用它来设置。
%    \begin{macrocode}
\if_bool:N \l_@@_caption_bool
  \@ifpackageloaded { varioref }
    { \ctex_varioref_hook: }
    {
      \cs_new_eq:NN \CTEX@save@refstepcounter \refstepcounter
      \RenewDocumentCommand \refstepcounter { m }
        {
          \CTEX@save@refstepcounter {#1}
          \CTEX@setcurrentlabel@n {#1}
        }
      \AtBeginDocument
        { \@ifpackageloaded { varioref } { \ctex_varioref_hook: } { } }
    }
\fi:
%    \end{macrocode}
%
% \subsubsection{模拟标准文档类格式}
%
% 下面使用 \CTeX 文档类的设置方式，重新模拟标准文档类直接定义或以
% \cs{@startsection} 设定的章节标题格式。
%
%    \begin{macrocode}
\keys_set:nn { ctex / part }
  {
    name        = \partname \space ,
    number      = \thepart ,
%<*article>
    format      = \raggedright ,
    nameformat  = \Large \bfseries ,
    aftername   = \par \nobreak ,
    titleformat = \huge \bfseries ,
    beforeskip  = -4ex ,
    afterskip   = 3ex
%</article>
%<*book|report>
    format      = \centering ,
    nameformat  = \huge \bfseries ,
    aftername   = \par \vskip 20 \p@ ,
    titleformat = \Huge \bfseries ,
    pagestyle   = plain
%</book|report>
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%<*book|report>
\keys_set:nn { ctex / chapter }
  {
    name        = \chaptername \space ,
    number      = \thechapter ,
    format      = \raggedright ,
    nameformat  = \huge \bfseries ,
    aftername   = \par \nobreak \vskip 20 \p@ ,
    titleformat = \Huge \bfseries ,
    beforeskip  = -50 \p@ ,
    afterskip   = 40 \p@ ,
    pagestyle   = plain
  }
%</book|report>
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_set:nn { ctex / section }
  {
    number      = \thesection ,
    format      = \Large \bfseries ,
    aftername   = \quad ,
    beforeskip  = -3.5ex \@plus -1ex \@minus -.2ex ,
    afterskip   = 2.3ex \@plus .2ex
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_set:nn { ctex / subsection }
  {
    number      = \thesubsection ,
    format      = \large \bfseries ,
    aftername   = \quad ,
    beforeskip  = -3.25ex \@plus -1ex \@minus -.2ex ,
    afterskip   = 1.5ex  \@plus .2ex
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_set:nn { ctex / subsubsection }
  {
    number      = \thesubsubsection ,
    format      = \normalsize \bfseries ,
    aftername   = \quad ,
    beforeskip  = -3.25ex \@plus -1ex \@minus -.2ex ,
    afterskip   = 1.5ex \@plus .2ex
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_set:nn { ctex / paragraph }
  {
    number      = \theparagraph ,
    format      = \normalsize \bfseries ,
    aftername   = \quad ,
    beforeskip  = 3.25ex \@plus 1ex \@minus .2ex ,
    afterskip   = -1em
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_set:nn { ctex / subparagraph }
  {
    number      = \thesubparagraph ,
    format      = \normalsize \bfseries ,
    aftername   = \quad ,
    beforeskip  = 3.25ex \@plus 1ex \@minus .2ex ,
    afterskip   = -1em ,
    indent      = \parindent
  }
%    \end{macrocode}
%
% 处理 \opt{sub3section} 与 \opt{sub4section} 的格式。
%    \begin{macrocode}
\int_compare:nNnT \g_@@_section_depth_flag > \c_two
  {
    \keys_set:nn { ctex / paragraph }
      {
        beforeskip = -3.25ex \@plus 1ex \@minus .2ex,
        afterskip = 1ex \@plus .2ex
      }
  }
\int_compare:nNnT \g_@@_section_depth_flag > \c_three
  {
    \keys_set:nn { ctex / subparagraph }
      {
        beforeskip = -3.25ex \@plus 1ex \@minus .2ex,
        afterskip = 1ex \@plus .2ex
      }
  }
\int_compare:nNnT \g_@@_section_depth_flag > \c_two
  {
    \keys_set:nn { ctex / subparagraph }
      { indent = \z@ }
  }
%    \end{macrocode}
%
% 处理附录的格式。
%    \begin{macrocode}
%<article>\keys_set:nn { ctex / appendix } { name = { } }
%    \end{macrocode}
%
% \subsubsection{汉化默认标题格式}
%
% 在 \opt{cap} 选项为 |true| 时，设置中文化的标题格式。
%    \begin{macrocode}
\if_bool:N \l_@@_caption_bool
  \keys_set:nn { ctex / part }
    {
      number      = \chinese { part } ,
%<*article>
      format      = \centering ,
      aftername   = \quad ,
      titleformat = \Large\bfseries ,
      beforeskip  = 4ex
%</article>
%<*book|report>
      titleformat = \huge \bfseries
%</book|report>
    }
%<*book|report>
  \keys_set:nn { ctex / chapter }
    {
      number      = \chinese { chapter } ,
      format      = \centering ,
      aftername   = \quad ,
      titleformat = \huge \bfseries
      beforeskip  = 50\p@ ,
    }
%</book|report>
  \keys_set:nn { ctex / section }
    {
      format     = \Large \bfseries \centering ,
      beforeskip = 3.5ex \@plus 1ex \@minus .2ex
    }
  \keys_set:nn { ctex / subsection }
    { beforeskip = 3.25ex \@plus 1ex \@minus .2ex }
  \keys_set:nn { ctex / subsubsection }
    { beforeskip = 3.25ex \@plus 1ex \@minus .2ex }
  \keys_set:nn { ctex / paragraph }
    { beforeskip = 3.25ex \@plus 1ex \@minus .2ex }
  \keys_set:nn { ctex / subparagraph }
    { beforeskip = 3.25ex \@plus 1ex \@minus .2ex }
  \str_if_eq:onTF { \l_@@_encoding_tl } { GBK }
    { \ctex_file_input:n { ctexcap-gbk.cfg } }
    { \ctex_file_input:n { ctexcap-utf8.cfg } }
\fi:
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|heading>
%<*style>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex.sty} 的 \opt{heading} 选项}
%
%    \begin{macrocode}
\msg_new:nnn { ctex } { not-standard-class }
  {
    None~of~the~standard~document~classes~was~loaded.\\
    ctex~may~not~work~as~expected.
  }
\bool_if:NTF \l_@@_heading_bool
  {
    \clist_map_inline:nn { article , book , report }
      {
        \@ifclassloaded {#1}
          { \clist_map_break:n { \tl_const:Nn \c_@@_class_tl {#1} } } { }
      }
    \tl_if_exist:NTF \c_@@_class_tl
      { \ctex_file_input:n { ctex- \c_@@_class_tl .def } }
      {
        \msg_warning:nn { ctex } { not-standard-class }
        \cs_if_exist:NTF \chapter
          {
            \cs_if_exist:NF \if@mainmatter
              { \cs_new_eq:NN \if@mainmatter \tex_iftrue:D }
            \ctex_file_input:n { ctex-book.def }
          }
          { \ctex_file_input:n { ctex-article.def } }
      }
  }
  {
    \bool_if:NT \l_@@_caption_bool
      {
        \str_if_eq:onTF { \l_@@_encoding_tl } { GBK }
          { \ctex_file_input:n { ctexcap-gbk.cfg } }
          { \ctex_file_input:n { ctexcap-utf8.cfg } }
      }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</style>
%<*UTF8|GBK>
%    \end{macrocode}
%
% \subsubsection{标题配置文件}
%
%    \begin{macrocode}
\keys_set:nn { ctex }
  {
    contentsname   = 目录 ,
    listfigurename = 插图 ,
    listtablename  = 表格 ,
    figurename     = 图 ,
    tablename      = 表 ,
    abstractname   = 摘要 ,
    indexname      = 索引 ,
    bibname        = 参考文献 ,
    appendixname   = 附录
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_if_exist:nnT { ctex / part } { name }
  {
    \keys_set:nn { ctex / part } { name = { 第 , 部分 } }
    \keys_if_exist:nnT { ctex / chapter } { name }
      { \keys_set:nn { ctex / chapter } { name = { 第 , 章 } } }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</UTF8|GBK>
%    \end{macrocode}
%
% \subsection{其它功能}
%
% \begin{macro}{\CTeX}
% \file{ctex-faq.sty} 中的定义是
% \begin{verbatim}
%   \DeclareRobustCommand\CTeX{$\mathbb{C}$\kern-.05em\TeX}
% \end{verbatim}
% 然而 \cs{mathbb} 未必有定义，这里就不采用它了，只定义最简单的形式。
% 同 \pkg{hologo} 宏包的设置类似，\CTeX{} 可以用在 \cs{csname} 和 PDF 书签中。
%    \begin{macrocode}
%<*class|style>
\NewDocumentCommand \CTeX { }
  { \ifincsname CTeX \else: C \TeX \fi: }
\AtBeginDocument
  {
    \cs_if_exist_use:NT \pdfstringdefDisableCommands
      { { \tl_set:Nn \CTeX { CTeX } } }
  }
%</class|style>
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/28}{\opt{captiondelimiter} 是过时选项。}
% \begin{macro}[internal]{captiondelimiter}
% 过时选项。
%    \begin{macrocode}
%<*class|style>
\keys_define:nn { ctex }
  {
    captiondelimiter .code:n =
      { \msg_warning:nn { ctex } { captiondelimiter } }
  }
\msg_new:nnn { ctex } { captiondelimiter }
  {
    Option~`captiondelimiter'~is~deprecated.\\
    You~can~load~the~package~`caption'~to~get~its~functionality.
  }
%</class|style>
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{列表环境的缩进}
%
% \begin{macro}[internal]{\verse,\quotation}
% 只在使用文档类的时候修改诗歌和引用环境的缩进。
%    \begin{macrocode}
%<*class|heading>
\ctex_patch_cmd:Nnn \verse { -1.5em } { -2 \ccwd }
\ctex_patch_cmd:Nnn \verse {  1.5em } {  2 \ccwd }
\ctex_patch_cmd:Nnn \quotation { 1.5em } { 2 \ccwd }
%</class|heading>
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%<*class|style>
%    \end{macrocode}
%
% \subsubsection{其它兼容性修改}
%
% \begin{macro}[internal]{\end}
% \changes{v2.0}{2014/03/09}
% {解决 \pkg{etoolbox} 与 \pkg{breqn} 关于 \cs{end} 的冲突。}
% \pkg{breqn} 宏包对 \cs{end} 作了如下处理，然而这个处理并不保险。
% \begin{verbatim}
%   \def\@tempa#1\endcsname#2\@nil{\def\latex@end##1{#2}}
%   \expandafter\@tempa\end{#1}\@nil
%   \def\end#1{\csname end#1\endcsname \latex@end{#1}}%
% \end{verbatim}
% \pkg{etoolbox} 在 \cs{end} 定义中的 \cs{csname} 前加入
% 钩子 |\csuse{@end@#1@hook}|。如果 \pkg{etoolbox} 先于 \pkg{breqn} 被载入（这
% 在使用 \cls{ctexart} 等文档类时几乎是必然的），|\csuse{@end@#1@hook}| 将会被
% 忽略，即 \cs{AtEndEnvironment} 失效。如果交换两个宏包的载入顺序，则
% \pkg{etoolbox} 会给出警告：\cs{AfterEndEnvironment} 失效，我们不打算处理这种
% 情况。我们通过一个特殊的环境来完成检查。
%    \begin{macrocode}
\newenvironment { @@_test_env }
  { \bool_gset_false:N \g_@@_tmp_bool } { }
\AtEndEnvironment { @@_test_env }
  { \bool_gset_true:N \g_@@_tmp_bool }
\group_begin:
\char_set_catcode_other:N \#
\cs_new_protected_nopar:Npn \ctex_fix_end_env_hook:
  {
    \begin { @@_test_env } \end { @@_test_env }
    \bool_if:NF \g_@@_tmp_bool
      {
        \ctex_patch_cmd:NnnTF \end { \csname end#1 \endcsname }
          {
            \csuse { @end@#1@hook }
            \csname end#1 \endcsname
          } { }
          {
            \ctex_preto_cmd:NnTF \end { \csuse { @end@#1@hook } }
              { } { \ctex_patch_failure:N \end }
          }
      }
  }
\group_end:
\AtBeginDocument { \ctex_fix_end_env_hook: }
%    \end{macrocode}
% \end{macro}
%
% \subsection{载入中文字体}
%
% \begin{macro}[internal]{\ctex_fontset_error:n}
% 字库不可用时给出紧急错误信息，停止读取定义文件。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_fontset_error:n #1
  { \msg_critical:nnn { ctex } { fontset-unavailable } {#1} }
\msg_new:nnn { ctex } { fontset-unavailable }
  { CTeX~fontset~`#1'~is~unavailable~in~current~mode. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ctex_load_fontset:}
% 如果用户没有指定字体，则探测操作系统，载入相应的字体配置。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_load_fontset:
  {
    \tl_if_empty:NTF \g_@@_fontset_tl
      {
        \ctex_detected_platform:
        \ctex_file_input:n { ctex-fontset- \g_@@_fontset_tl .def }
      }
      {
        \file_if_exist:nTF { ctex-fontset- \g_@@_fontset_tl .def }
          { \ctex_file_input:n { ctex-fontset- \g_@@_fontset_tl .def } }
          {
            \use:x
              {
                \ctex_detected_platform:
                \msg_error:nnxx { ctex } { fontset-not-found }
                  { \g_@@_fontset_tl } { \exp_not:N \g_@@_fontset_tl }
              }
            \ctex_file_input:n { ctex-fontset- \g_@@_fontset_tl .def }
          }
      }
  }
\@onlypreamble \ctex_load_fontset:
\msg_new:nnnn { ctex } { fontset-not-found }
  {
    CTeX~fontset~`#1'~could~not~be~found.\\
    Fontset~`#2'~will~be~used~instead.
  }
  { You~may~run~`mktexlsr'~firstly. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{fontset}
% 在导言区通过 \cs{ctexset} 载入中文字库的选项。
%    \begin{macrocode}
\keys_define:nn { ctex }
  {
    fontset .code:n =
      {
        \str_if_eq_x:nnTF {#1} { none }
          { \msg_warning:nnn { ctex } { invalid-value } {#1} }
          {
            \str_if_eq:onTF { \g_@@_fontset_tl } { none }
              {
                \tl_gset:Nx \g_@@_fontset_tl {#1}
                \ctex_load_fontset:
              }
              {
                \msg_error:nnxx { ctex } { fontset-loaded }
                  { \g_@@_fontset_tl } {#1}
              }
          }
      }
  }
\msg_new:nnnn { ctex } { fontset-loaded }
  {
    CTeX~fontset~`#1'~has~been~loaded.
    \str_if_eq:nnF {#1} {#2} { \\ Fontset~`#2'~will~be~ignored. }
  }
  { Only~one~fontset~can~be~loaded~in~the~preamble. }
\AtBeginDocument
  {
    \keys_define:nn { ctex }
      { fontset .code:n = \msg_warning:nn { ctex } { invalid-option } }
  }
%    \end{macrocode}
% \end{macro}
%
% 载入中文字库。
%    \begin{macrocode}
\str_if_eq:onF { \g_@@_fontset_tl } { none }
  { \ctex_load_fontset: }
%    \end{macrocode}
%
% \subsection{宏包配置文件}
%
% \subsubsection{\pkg{ctex.cfg}}
%
%    \begin{macrocode}
\ctex_at_end:n { \ctex_file_input:n { ctex.cfg } }
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|style>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*config>
%%
%</config>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctexopts.cfg}}
%
%    \begin{macrocode}
%<*ctexopts>
%%
%% \keys_set:nn { ctex / option } { fontset = windows }
%</ctexopts>
%    \end{macrocode}
%
% \subsection{字体定义文件}
%
% \subsubsection{传统定义方式}
%
%    \begin{macrocode}
%<*c19|c70>
%%
%% Chinese characters
%%
%<c19>%% character set: GBK (extension of GB 2312)
%<c70>%% character set: Unicode
%% font encoding: Unicode
%%
%</c19|c70>
%    \end{macrocode}
%
%    \begin{macrocode}
%<rm&c19>\DeclareFontFamily{C19}{rm}{\hyphenchar\font\m@ne}
%<rm&c70>\DeclareFontFamily{C70}{rm}{\hyphenchar\font\m@ne}
%<sf&c19>\DeclareFontFamily{C19}{sf}{\hyphenchar\font\m@ne}
%<sf&c70>\DeclareFontFamily{C70}{sf}{\hyphenchar\font\m@ne}
%<tt&c19>\DeclareFontFamily{C19}{tt}{\hyphenchar\font\m@ne}
%<tt&c70>\DeclareFontFamily{C70}{tt}{\hyphenchar\font\m@ne}
%    \end{macrocode}
%
%    \begin{macrocode}
%<*rm>
%<*c19>
\DeclareFontShape{C19}{rm}{m}{n}{<-> CJK * gbksong}{\CJKnormal}
\DeclareFontShape{C19}{rm}{b}{n}{<-> CJK * gbkhei}{\CJKnormal}
\DeclareFontShape{C19}{rm}{bx}{n}{<-> CJK * gbkhei}{\CJKnormal}
\DeclareFontShape{C19}{rm}{m}{sl}{<-> CJK * gbksongsl}{\CJKnormal}
\DeclareFontShape{C19}{rm}{b}{sl}{<-> CJK * gbkheisl}{\CJKnormal}
\DeclareFontShape{C19}{rm}{bx}{sl}{<-> CJK * gbkheisl}{\CJKnormal}
\DeclareFontShape{C19}{rm}{m}{it}{<-> CJK * gbkkai}{\CJKnormal}
\DeclareFontShape{C19}{rm}{b}{it}{<-> CJKb * gbkkai}{\CJKbold}
\DeclareFontShape{C19}{rm}{bx}{it}{<-> CJKb * gbkkai}{\CJKbold}
%</c19>
%<*c70>
\DeclareFontShape{C70}{rm}{m}{n}{<-> CJK * unisong}{\CJKnormal}
\DeclareFontShape{C70}{rm}{b}{n}{<-> CJK * unihei}{\CJKnormal}
\DeclareFontShape{C70}{rm}{bx}{n}{<-> CJK * unihei}{\CJKnormal}
\DeclareFontShape{C70}{rm}{m}{sl}{<-> CJK * unisongsl}{\CJKnormal}
\DeclareFontShape{C70}{rm}{b}{sl}{<-> CJK * uniheisl}{\CJKnormal}
\DeclareFontShape{C70}{rm}{bx}{sl}{<-> CJK * uniheisl}{\CJKnormal}
\DeclareFontShape{C70}{rm}{m}{it}{<-> CJK * unikai}{\CJKnormal}
\DeclareFontShape{C70}{rm}{b}{it}{<-> CJKb * unikai}{\CJKbold}
\DeclareFontShape{C70}{rm}{bx}{it}{<-> CJKb * unikai}{\CJKbold}
%</c70>
%</rm>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*sf>
%<*c19>
\DeclareFontShape{C19}{sf}{m}{n}{<-> CJK * gbkyou}{\CJKnormal}
\DeclareFontShape{C19}{sf}{b}{n}{<-> CJKb * gbkyou}{\CJKbold}
\DeclareFontShape{C19}{sf}{bx}{n}{<-> CJKb * gbkyou}{\CJKbold}
\DeclareFontShape{C19}{sf}{m}{sl}{<-> CJK * gbkyousl}{\CJKnormal}
\DeclareFontShape{C19}{sf}{b}{sl}{<-> CJKb * gbkyousl}{\CJKbold}
\DeclareFontShape{C19}{sf}{bx}{sl}{<-> CJKb * gbkyousl}{\CJKbold}
\DeclareFontShape{C19}{sf}{m}{it}{<-> CJK * gbkyou}{\CJKnormal}
\DeclareFontShape{C19}{sf}{b}{it}{<-> CJKb * gbkyou}{\CJKbold}
\DeclareFontShape{C19}{sf}{bx}{it}{<-> CJKb * gbkyou}{\CJKbold}
%</c19>
%<*c70>
\DeclareFontShape{C70}{sf}{m}{n}{<-> CJK * uniyou}{\CJKnormal}
\DeclareFontShape{C70}{sf}{b}{n}{<-> CJKb * uniyou}{\CJKbold}
\DeclareFontShape{C70}{sf}{bx}{n}{<-> CJKb * uniyou}{\CJKbold}
\DeclareFontShape{C70}{sf}{m}{sl}{<-> CJK * uniyousl}{\CJKnormal}
\DeclareFontShape{C70}{sf}{b}{sl}{<-> CJKb * uniyousl}{\CJKbold}
\DeclareFontShape{C70}{sf}{bx}{sl}{<-> CJKb * uniyousl}{\CJKbold}
\DeclareFontShape{C70}{sf}{m}{it}{<-> CJK * uniyou}{\CJKnormal}
\DeclareFontShape{C70}{sf}{b}{it}{<-> CJKb * uniyou}{\CJKbold}
\DeclareFontShape{C70}{sf}{bx}{it}{<-> CJKb * uniyou}{\CJKbold}
%</c70>
%</sf>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*tt>
%<*c19>
\DeclareFontShape{C19}{tt}{m}{n}{<-> CJK * gbkfs}{\CJKnormal}
\DeclareFontShape{C19}{tt}{b}{n}{<-> CJKb * gbkfs}{\CJKbold}
\DeclareFontShape{C19}{tt}{bx}{n}{<-> CJKb * gbkfs}{\CJKbold}
\DeclareFontShape{C19}{tt}{m}{sl}{<-> CJK * gbkfssl}{\CJKnormal}
\DeclareFontShape{C19}{tt}{b}{sl}{<-> CJKb * gbkfssl}{\CJKbold}
\DeclareFontShape{C19}{tt}{bx}{sl}{<-> CJKb * gbkfssl}{\CJKbold}
\DeclareFontShape{C19}{tt}{m}{it}{<-> CJK * gbkfs}{\CJKnormal}
\DeclareFontShape{C19}{tt}{b}{it}{<-> CJKb * gbkfs}{\CJKbold}
\DeclareFontShape{C19}{tt}{bx}{it}{<-> CJKb * gbkfs}{\CJKbold}
%</c19>
%<*c70>
\DeclareFontShape{C70}{tt}{m}{n}{<-> CJK * unifs}{\CJKnormal}
\DeclareFontShape{C70}{tt}{b}{n}{<-> CJKb * unifs}{\CJKbold}
\DeclareFontShape{C70}{tt}{bx}{n}{<-> CJKb * unifs}{\CJKbold}
\DeclareFontShape{C70}{tt}{m}{sl}{<-> CJK * unifssl}{\CJKnormal}
\DeclareFontShape{C70}{tt}{b}{sl}{<-> CJKb * unifssl}{\CJKbold}
\DeclareFontShape{C70}{tt}{bx}{sl}{<-> CJKb * unifssl}{\CJKbold}
\DeclareFontShape{C70}{tt}{m}{it}{<-> CJK * unifs}{\CJKnormal}
\DeclareFontShape{C70}{tt}{b}{it}{<-> CJKb * unifs}{\CJKbold}
\DeclareFontShape{C70}{tt}{bx}{it}{<-> CJKb * unifs}{\CJKbold}
%</c70>
%</tt>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*fontset>
%<*windows>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-fontset-windows.def}}
%
%    \begin{macrocode}
\pdftex_if_engine:TF
  {
    \ctex_zhmap_case:nnn
      {
        \ctex_punct_set:n { windowns }
        \setCJKmainfont
          [ BoldFont = simhei.ttf , ItalicFont = simkai.ttf ] { simsun.ttc }
        \file_if_exist:nTF { C:/boot.ini }
          {
            \setCJKsansfont { simhei.ttf }
            \ctex_punct_map_family:nn { \CJKsfdefault } { zhhei }
          }
          {
            \file_if_exist:nTF { C:/Windows/Fonts/msyh.ttc }
              {
                \setCJKsansfont [ BoldFont = msyhbd.ttc ] { msyh.ttc }
                \setCJKfamilyfont { zhyahei }
                  [ BoldFont = msyhbd.ttc ] { msyh.ttc }
              }
              {
                \setCJKsansfont [ BoldFont = msyhbd.ttf ] { msyh.ttf }
                \setCJKfamilyfont { zhyahei }
                  [ BoldFont = msyhbd.ttf ] { msyh.ttf }
              }
            \ctex_punct_map_family:nn { \CJKsfdefault } { zhyahei }
            \ctex_punct_map_bfseries:nn { \CJKsfdefault , zhyahei } { zhyaheib }
          }
        \setCJKmonofont { simfang.ttf }
        \setCJKfamilyfont { zhkai }  { simkai.ttf }
        \setCJKfamilyfont { zhfs }   { simfang.ttf }
        \setCJKfamilyfont { zhsong } { simsun.ttc }
        \setCJKfamilyfont { zhhei }  { simhei.ttf }
        \setCJKfamilyfont { zhli }   { simli.ttf }
        \setCJKfamilyfont { zhyou }  { simyou.ttf }
        \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
        \ctex_punct_map_family:nn { \CJKttdefault } { zhfs }
        \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { zhwinfonts }
        \ctex_punct_set:n { windowns }
        \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
        \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
      }
      {
        \tl_set:Nn \CJKrmdefault { rm }
        \tl_set:Nn \CJKsfdefault { sf }
        \tl_set:Nn \CJKttdefault { tt }
      }
  }
  {
    \file_if_exist:nTF { C:/boot.ini }
      {
        \setCJKmainfont
          [ BoldFont = SimHei , ItalicFont = KaiTi_GB2312 ] { SimSun }
        \setCJKsansfont { SimHei }
        \setCJKmonofont { FangSong_GB2312 }
        \setCJKfamilyfont { zhkai } { KaiTi_GB2312 }
        \setCJKfamilyfont { zhfs }  { FangSong_GB2312 }
      }
      {
        \setCJKmainfont
          [ BoldFont = SimHei , ItalicFont = KaiTi ] { SimSun }
        \setCJKsansfont
          [ BoldFont = { *~Bold } ] { Microsoft~YaHei }
        \setCJKmonofont { FangSong }
        \setCJKfamilyfont { zhkai } { KaiTi }
        \setCJKfamilyfont { zhfs }  { FangSong }
      }
    \setCJKfamilyfont { zhsong }  { SimSun }
    \setCJKfamilyfont { zhhei }   { SimHei }
    \setCJKfamilyfont { zhli }    { LiSu }
    \setCJKfamilyfont { zhyou }   { YouYuan }
    \setCJKfamilyfont { zhyahei }
      [ BoldFont = { *~Bold } ] { Microsoft~YaHei }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</windows>
%<*adobe>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-fontset-adobe.def}}
%
% \cs{pdfmapline} 不支持 OpenType 字体，因而 \opt{adobe} 字体集在 pdf 模式下
% 就没有定义。\opt{fandol} 的情况类似。
%    \begin{macrocode}
\pdftex_if_engine:TF
  {
    \ctex_if_pdfmode:TF
      { \ctex_fontset_error:n { adobe } }
      {
        \ctex_zhmap_case:nnn
          {
            \setCJKmainfont
              [
                      cmap = UniGB-UTF16-H ,
                  BoldFont = AdobeHeitiStd-Regular.otf ,
                ItalicFont = AdobeKaitiStd-Regular.otf
              ] { AdobeSongStd-Light.otf }
            \setCJKsansfont [ cmap = UniGB-UTF16-H ] { AdobeHeitiStd-Regular.otf }
            \setCJKmonofont [ cmap = UniGB-UTF16-H ] { AdobeFangsongStd-Regular.otf }
            \setCJKfamilyfont { zhsong }
              [ cmap = UniGB-UTF16-H ] { AdobeSongStd-Light.otf }
            \setCJKfamilyfont { zhhei }
              [ cmap = UniGB-UTF16-H ] { AdobeHeitiStd-Regular.otf }
            \setCJKfamilyfont { zhkai }
              [ cmap = UniGB-UTF16-H ] { AdobeKaitiStd-Regular.otf }
            \setCJKfamilyfont { zhfs }
              [ cmap = UniGB-UTF16-H ] { AdobeFangsongStd-Regular.otf }
            \ctex_punct_set:n { adobe }
            \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
            \ctex_punct_map_family:nn { \CJKsfdefault } { zhhei }
            \ctex_punct_map_family:nn { \CJKttdefault } { zhfs }
            \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
            \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
          }
          {
            \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { zhadobefonts }
            \ctex_punct_set:n { adobe }
            \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
            \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
            \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
          }
          { \ctex_fontset_error:n { adobe } }
      }
  }
  {
    \setCJKmainfont
      [
          BoldFont = AdobeHeitiStd-Regular ,
        ItalicFont = AdobeKaitiStd-Regular
      ] { AdobeSongStd-Light }
    \setCJKsansfont { AdobeHeitiStd-Regular}
    \setCJKmonofont { AdobeFangsongStd-Regular}
    \setCJKfamilyfont { zhsong } { AdobeSongStd-Light }
    \setCJKfamilyfont { zhhei }  { AdobeHeitiStd-Regular }
    \setCJKfamilyfont { zhfs }   { AdobeFangsongStd-Regular }
    \setCJKfamilyfont { zhkai }  { AdobeKaitiStd-Regular }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</adobe>
%<*fandol>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-fontset-fandol.def}}
%
%    \begin{macrocode}
\pdftex_if_engine:TF
  {
    \ctex_if_pdfmode:TF
      { \ctex_fontset_error:n { fandol } }
      {
        \ctex_zhmap_case:nnn
          {
            \setCJKmainfont
              [
                      cmap = UniGB-UTF16-H ,
                  BoldFont = FandolSong-Bold.otf ,
                ItalicFont = FandolKai-Regular.otf
              ] { FandolSong-Regular.otf }
            \setCJKsansfont
              [
                    cmap = UniGB-UTF16-H ,
                BoldFont = FandolHei-Bold.otf
              ] { FandolHei-Regular.otf }
            \setCJKmonofont [ cmap = UniGB-UTF16-H ] { FandolFang-Regular.otf }
            \setCJKfamilyfont { zhsong }
              [
                    cmap = UniGB-UTF16-H ,
                BoldFont = FandolSong-Bold.otf
              ] { FandolSong-Regular.otf }
            \setCJKfamilyfont { zhhei }
              [
                    cmap = UniGB-UTF16-H ,
                BoldFont = FandolHei-Bold.otf
              ] { FandolHei-Regular.otf }
            \setCJKfamilyfont { zhfs }
              [ cmap = UniGB-UTF16-H ] { FandolFang-Regular.otf }
            \setCJKfamilyfont { zhkai }
              [ cmap = UniGB-UTF16-H ] { FandolKai-Regular.otf }
            \ctex_punct_set:n { fandol }
            \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
            \ctex_punct_map_family:nn { \CJKsfdefault } { zhhei }
            \ctex_punct_map_family:nn { \CJKttdefault } { zhfs }
            \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
            \ctex_punct_map_bfseries:nn { \CJKrmdefault , zhsong } { zhsongb }
            \ctex_punct_map_bfseries:nn { \CJKsfdefault , zhhei } { zhheib }
          }
          {
            \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { zhfandolfonts }
            \ctex_punct_set:n { fandol }
            \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
            \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
            \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
          }
          { \ctex_fontset_error:n { fandol } }
      }
  }
  {
    \setCJKmainfont
      [ BoldFont = FandolSong-Bold , ItalicFont = FandolKai ] { FandolSong-Regular }
    \setCJKsansfont [ BoldFont = FandolHei-Bold ] { FandolHei-Regular }
    \setCJKmonofont { FandolFang }
    \setCJKfamilyfont { zhsong } [ BoldFont = FandolSong-Bold ] { FandolSong }
    \setCJKfamilyfont { zhhei }  [ BoldFont = FandolHei-Bold ]  { FandolHei }
    \setCJKfamilyfont { zhfs }  { FandolFang }
    \setCJKfamilyfont { zhkai } { FandolKai }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</fandol>
%<*mac>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-fontset-mac.def}}
%
% OS X Mavericks (10.9) 预装的主要简体中文字体如下^^A
% \footnote{\url{http://support.apple.com/kb/HT5944}}：
% \begin{verbatim}
%   /Library/Fonts/Baoli.ttc: 报隶-简,Baoli SC:style=Regular
%   /Library/Fonts/Hannotate.ttc: 手札体-简,Hannotate SC:style=Bold
%   /Library/Fonts/Hannotate.ttc: 手札体-简,Hannotate SC:style=Regular
%   /Library/Fonts/Hanzipen.ttc: 翩翩体-简,HanziPen SC:style=Bold
%   /Library/Fonts/Hanzipen.ttc: 翩翩体-简,HanziPen SC:style=Regular
%   /Library/Fonts/Hei.ttf: Hei
%   /Library/Fonts/Hiragino Sans GB W3.otf: 冬青黑体简体中文 W3,Hiragino Sans GB W3
%   /Library/Fonts/Hiragino Sans GB W6.otf: 冬青黑体简体中文 W6,Hiragino Sans GB W6
%   /Library/Fonts/Kai.ttf: Kai
%   /Library/Fonts/Kaiti.ttc: STKaiti
%   /Library/Fonts/Kaiti.ttc: 楷体-简,Kaiti SC:style=Black
%   /Library/Fonts/Kaiti.ttc: 楷体-简,Kaiti SC:style=Bold
%   /Library/Fonts/Kaiti.ttc: 楷体-简,Kaiti SC:style=Regular
%   /Library/Fonts/Lantinghei.ttc: 兰亭黑-简,Lantinghei SC:style=Demibold
%   /Library/Fonts/Lantinghei.ttc: 兰亭黑-简,Lantinghei SC:style=Heavy
%   /Library/Fonts/Lantinghei.ttc: 兰亭黑-简,Lantinghei SC:style=Extralight
%   /Library/Fonts/Libian.ttc: 隶变-简,Libian SC
%   /Library/Fonts/Songti.ttc: STSong
%   /Library/Fonts/Songti.ttc: 宋体-简,Songti SC:style=Black
%   /Library/Fonts/Songti.ttc: 宋体-简,Songti SC:style=Bold
%   /Library/Fonts/Songti.ttc: 宋体-简,Songti SC:style=Light
%   /Library/Fonts/Songti.ttc: 宋体-简,Songti SC:style=Regular
%   /Library/Fonts/WawaSC-Regular.otf: 娃娃体-简,Wawati SC
%   /Library/Fonts/WeibeiSC-Bold.otf: 魏碑-简,Weibei SC
%   /Library/Fonts/Xingkai.ttc: 行楷-简,Xingkai SC:style=Bold
%   /Library/Fonts/Xingkai.ttc: 行楷-简,Xingkai SC:style=Light
%   /Library/Fonts/Yuanti.ttc: 圆体-简,Yuanti SC:style=Bold
%   /Library/Fonts/Yuanti.ttc: 圆体-简,Yuanti SC:style=Light
%   /Library/Fonts/Yuanti.ttc: 圆体-简,Yuanti SC:style=Regular
%   /Library/Fonts/YuppySC-Regular.otf: 雅痞-简,Yuppy SC
%   /Library/Fonts/华文仿宋.ttf: STFangsong
%   /Library/Fonts/华文细黑.ttf: STHeiti:style=Light
%   /Library/Fonts/华文黑体.ttf: STHeiti:style=Regular
%   /System/Library/Fonts/STHeiti Light.ttc: 黑体-简,Heiti SC:style=Light
%   /System/Library/Fonts/STHeiti Medium.ttc: 黑体-简,Heiti SC:style=Medium
% \end{verbatim}
% 在 \dvipdfmx{} 下，可以通过下述方式使用华文宋体和华文楷体：
% \begin{verbatim}
%   \special{pdf:mapline unisong@Unicode@ unicode :4:Songti.ttc}
%   \special{pdf:mapline unikai@Unicode@  unicode :4:Kaiti.ttc}
% \end{verbatim}
% 而 \cs{pdfmapline} 似乎不支持带索引的 \texttt{ttc} 字体，\file{Songti.ttc} 默认
% 使用的是 Songti SC Black，\file{Kaiti.ttc} 默认使用的是 Kaiti SC Black。
% 华文黑体不能通过这种方式使用：
% \begin{verbatim}
%   \special{pdf:mapline unihei@Unicode@ unicode \detokenize{华文黑体}.ttf}
% \end{verbatim}
% \dvipdfmx{} 不能生成 PDF，报下述错误：
% \begin{verbatim}
%   ** WARNING ** UCS-4 TrueType cmap table...
%   ** ERROR ** Unable to read OpenType/TrueType Unicode cmap table.
% \end{verbatim}
% 如果将 CMap 改为 UniGB-UTF16-H，错误信息是
% \begin{verbatim}
%   ** WARNING ** No usable TrueType cmap table found for font "华文黑体.ttf".
%   ** WARNING ** CID character collection for this font is set to "Adobe-GB1"
%   ** ERROR ** Cannot continue without this...
% \end{verbatim}
% 在 \pdfTeX{} 下生成的 PDF 只有方框^^A
% \footnote{\url{http://www.newsmth.net/bbscon.php?bid=460&id=312640}}。
% 华文细黑和华文仿宋的情况类似。
%    \begin{macrocode}
\pdftex_if_engine:TF
  { \ctex_fontset_error:n { mac } }
  {
    \setCJKmainfont [ BoldFont = STHeiti , ItalicFont = STKaiti ]  { STSong }
    \setCJKsansfont [ BoldFont = STHeiti ] { STXihei }
    \setCJKmonofont { STFangsong }
    \setCJKfamilyfont { zhsong } { STSong }
    \setCJKfamilyfont { zhhei }  { STHeiti }
    \setCJKfamilyfont { zhfs }   { STFangsong }
    \setCJKfamilyfont { zhkai }  { STKaiti }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</mac>
%<*founder>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-fontset-founder.def}}
%
%    \begin{macrocode}
\pdftex_if_engine:TF
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont
          [ BoldFont = FZXBSK.TTF , ItalicFont = FZKTK.TTF ] { FZSSK.TTF }
        \setCJKsansfont [ BoldFont = FZHTK.TTF ] { FZXH1K.TTF }
        \setCJKmonofont { FZFSK.TTF }
        \setCJKfamilyfont { zhsong } [ BoldFont = FZXBSK.TTF ] { FZSSK.TTF }
        \setCJKfamilyfont { zhhei }  { FZHTK.TTF }
        \setCJKfamilyfont { zhkai }  { FZKTK.TTF }
        \setCJKfamilyfont { zhfs }   { FZFSK.TTF }
        \setCJKfamilyfont { zhli }   { FZLSK.TTF }
        \setCJKfamilyfont { zhyou } [ BoldFont = FZY3K.TTF ] { FZY1K.TTF }
        \ctex_punct_set:n { founder }
        \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
        \ctex_punct_map_family:nn { \CJKsfdefault } { zhheil }
        \ctex_punct_map_family:nn { \CJKttdefault } { zhfs }
        \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault , zhsong } { zhsongb }
        \ctex_punct_map_bfseries:nn { \CJKsfdefault } { zhhei }
        \ctex_punct_map_bfseries:nn { zhyou } { zhyoub }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { zhfounderfonts }
        \ctex_punct_set:n { founder }
        \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
        \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
      }
      { \ctex_fontset_error:n { founder } }
  }
  {
    \setCJKmainfont
      [ BoldFont = FZXiaoBiaoSong-B05 , ItalicFont = FZKai-Z03 ] { FZShuSong-Z01 }
%    \end{macrocode}
%
% 在 WPS For Linux 附带的 5.00 版和家庭版 5.20 版的“方正细黑一\_GBK”的字体名称
% 是 |FZXiHeiI-Z08|。但在网上发现不少文档和资料都是 \verb*|FZXiHei I-Z08|，而在
% 官方资料《2013 方正字库字体样张》中对应的英文名字是 \verb*|FZXiHei I|。可以用
% Postscript 名字 |FZXH1K--GBK1-0| 来统一。经测试时发现（WPS 中的字体），\XeTeX{}
% 找该字体时会出现明显的延迟，而用字体文件名 |FZXH1K.TTF| 又可能会出现大小写问题，
% 遂采用汉字名称。由于 \pkg{luaotfload} 不支持汉字名称，故使用 Postscript 名字，
% 速度不受影响。
%    \begin{macrocode}
    \setCJKsansfont [ BoldFont = FZHei-B01 ]
      { \xetex_if_engine:TF { 方正细黑一_GBK } { FZXH1K--GBK1-0 } }
    \setCJKmonofont { FZFangSong-Z02 }
    \setCJKfamilyfont { zhsong } [ BoldFont = FZXiaoBiaoSong-B05 ] { FZShuSong-Z01 }
    \setCJKfamilyfont { zhhei }  { FZHei-B01 }
    \setCJKfamilyfont { zhkai }  { FZKai-Z03 }
    \setCJKfamilyfont { zhfs }   { FZFangSong-Z02 }
    \setCJKfamilyfont { zhli }   { FZLiShu-S01 }
    \setCJKfamilyfont { zhyou } [ BoldFont = FZZhunYuan-M02 ] { FZXiYuan-M01 }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</founder>
%<*ubuntu>
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-fontset-ubuntu.def}}
%
% 以下根据 Ubuntu 12.04 的中文字体情况设置。CMap 不清楚应该是什么，指定为
% UniGB-UTF16-H 还是有警告：
% \begin{verbatim}
%   ** WARNING ** UCS-4 TrueType cmap table...
% \end{verbatim}
% 需要注意的是 \file{umint.ttc} 和 \file{ukai.ttc} 看起来像有四种字形的样子，但
% 其实只有“令”和“骨”这区区两个字有新字形，其余都取旧字形^^A
% \footnote{\url{http://code.google.com/p/ctex-kit/source/detail?r=578}}。
%    \begin{macrocode}
\pdftex_if_engine:TF
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont
          [ BoldFont = wqy-zenhei.ttc , ItalicFont = ukai.ttc ] { uming.ttc }
        \setCJKsansfont { wqy-zenhei.ttc }
        \setCJKmonofont { uming.ttc }
        \setCJKfamilyfont { zhsong } { uming.ttc }
        \setCJKfamilyfont { zhhei }  { wqy-zenhei.ttc }
        \setCJKfamilyfont { zhkai }  { ukai.ttc }
        \ctex_punct_set:n { ubuntu }
        \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
        \ctex_punct_map_family:nn { \CJKsfdefault } { zhhei }
        \ctex_punct_map_family:nn { \CJKttdefault } { zhsong }
        \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhsong } { zhubuntufonts }
        \ctex_punct_set:n { ubuntu }
        \ctex_punct_map_family:nn { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei }
        \ctex_punct_map_itshape:nn { \CJKrmdefault } { zhkai }
      }
      { \ctex_fontset_error:n { ubuntu } }
  }
  {
    \setCJKmainfont [ ItalicFont = AR~PL~UKai~CN ] { AR~PL~UMing~CN }
    \setCJKsansfont { WenQuanYi~Zen~Hei }
    \setCJKmonofont { AR~PL~UMing~CN }
    \setCJKfamilyfont { zhsong } { AR~PL~UMing~CN }
    \setCJKfamilyfont { zhhei }  { WenQuanYi~Zen~Hei }
    \setCJKfamilyfont { zhkai }  { AR~PL~UKai~CN }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</ubuntu>
%    \end{macrocode}
%
% \subsubsection{中文字体命令}
%
%    \begin{macrocode}
\NewDocumentCommand \songti   { } { \CJKfamily { zhsong } }
\NewDocumentCommand \heiti    { } { \CJKfamily { zhhei } }
%<!ubuntu>\NewDocumentCommand \fangsong { } { \CJKfamily { zhfs } }
\NewDocumentCommand \kaishu   { } { \CJKfamily { zhkai } }
%<*windows|founder>
\NewDocumentCommand \lishu    { } { \CJKfamily { zhli } }
\NewDocumentCommand \youyuan  { } { \CJKfamily { zhyou } }
%</windows|founder>
%<windows>\NewDocumentCommand \yahei    { } { \CJKfamily { zhyahei } }
%    \end{macrocode}
%
%    \begin{macrocode}
%</fontset>
%<*zhmap>
%    \end{macrocode}
%
% \subsubsection{\pkg{zhmetrics} 的字体映射}
%
% 确认 \cs{catcode}，没有重复载入检查。
%    \begin{macrocode}
\begingroup\catcode61\catcode48\catcode32=10\relax%
  \catcode 35=6 % #
  \catcode123=1 % {
  \catcode125=2 % }
  \toks0{\endlinechar=\the\endlinechar\relax}%
  \toks2{\endlinechar=13 }%
  \def\x#1 #2 {%
    \toks0\expandafter{\the\toks0 \catcode#1=\the\catcode#1\relax}%
    \toks2\expandafter{\the\toks2 \catcode#1=#2 }}%
  \x  13  5 % carriage return
  \x  32 10 % space
  \x  35  6 % #
  \x  40 12 % (
  \x  41 12 % )
  \x  45 12 % -
  \x  46 12 % .
  \x  47 12 % /
  \x  58 12 % :
  \x  60 12 % <
  \x  61 12 % =
  \x  64 11 % @
  \x  91 12 % [
  \x  93 12 % ]
  \x 123  1 % {
  \x 125  2 % }
  \edef\x#1{\endgroup%
    \edef\noexpand#1{%
      \the\toks0 %
      \let\noexpand\noexpand\noexpand#1%
          \noexpand\noexpand\noexpand\undefined%
      \noexpand\noexpand\noexpand\endinput}%
    \the\toks2}%
\expandafter\x\csname ctex@zhmap@endinput\endcsname
%    \end{macrocode}
%
%    \begin{macrocode}
\input ifpdf.sty\relax
%    \end{macrocode}
%
% 提供非 \LaTeX{} 格式下的 \cs{ProvidesFile}。
%    \begin{macrocode}
\begingroup
\expandafter\ifx\csname ProvidesFile\endcsname\relax
  \long\def\x#1\ProvidesFile#2[#3]{%
    #1%
    \immediate\write-1{File: #2 #3}%
    \expandafter\xdef\csname ver@#2\endcsname{#3}}
  \expandafter\x%
\fi
\endgroup
%    \end{macrocode}
%
% \paragraph{\pkg{zhwinfonts.tex}}
%
%    \begin{macrocode}
%<*windows>
\ProvidesFile{zhwinfonts.tex}%
  [2014/06/03 v2.0 Windows font map loader for pdfTeX and DVIPDFMx (CTEX)]

\ifpdf
  \pdfmapline{=gbk@UGBK@     <simsun.ttc}
  \pdfmapline{=gbksong@UGBK@ <simsun.ttc}
  \pdfmapline{=gbkkai@UGBK@  <simkai.ttf}
  \pdfmapline{=gbkhei@UGBK@  <simhei.ttf}
  \pdfmapline{=gbkfs@UGBK@   <simfang.ttf}
  \pdfmapline{=gbkli@UGBK@   <simli.ttf}
  \pdfmapline{=gbkyou@UGBK@  <simyou.ttf}

  \pdfmapline{=cyberb@Unicode@  <simsun.ttc}
  \pdfmapline{=unisong@Unicode@ <simsun.ttc}
  \pdfmapline{=unikai@Unicode@  <simkai.ttf}
  \pdfmapline{=unihei@Unicode@  <simhei.ttf}
  \pdfmapline{=unifs@Unicode@   <simfang.ttf}
  \pdfmapline{=unili@Unicode@   <simli.ttf}
  \pdfmapline{=uniyou@Unicode@  <simyou.ttf}

  \pdfmapline{=gbksongsl@UGBK@ <simsun.ttc}
  \pdfmapline{=gbkkaisl@UGBK@  <simkai.ttf}
  \pdfmapline{=gbkheisl@UGBK@  <simhei.ttf}
  \pdfmapline{=gbkfssl@UGBK@   <simfang.ttf}
  \pdfmapline{=gbklisl@UGBK@   <simli.ttf}
  \pdfmapline{=gbkyousl@UGBK@  <simyou.ttf}

  \pdfmapline{=unisongsl@Unicode@ <simsun.ttc}
  \pdfmapline{=unikaisl@Unicode@  <simkai.ttf}
  \pdfmapline{=uniheisl@Unicode@  <simhei.ttf}
  \pdfmapline{=unifssl@Unicode@   <simfang.ttf}
  \pdfmapline{=unilisl@Unicode@   <simli.ttf}
  \pdfmapline{=uniyousl@Unicode@  <simyou.ttf}

\else
  \special{pdf:mapline gbk@UGBK@     unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline gbksong@UGBK@ unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline gbkkai@UGBK@  unicode simkai.ttf -v 70}
  \special{pdf:mapline gbkhei@UGBK@  unicode simhei.ttf -v 150}
  \special{pdf:mapline gbkfs@UGBK@   unicode simfang.ttf -v 50}
  \special{pdf:mapline gbkli@UGBK@   unicode simli.ttf -v 150}
  \special{pdf:mapline gbkyou@UGBK@  unicode simyou.ttf -v 60}

  \special{pdf:mapline cyberb@Unicode@  unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline unisong@Unicode@ unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline unikai@Unicode@  unicode simkai.ttf -v 70}
  \special{pdf:mapline unihei@Unicode@  unicode simhei.ttf -v 150}
  \special{pdf:mapline unifs@Unicode@   unicode simfang.ttf -v 50}
  \special{pdf:mapline unili@Unicode@   unicode simli.ttf -v 150}
  \special{pdf:mapline uniyou@Unicode@  unicode simyou.ttf -v 60}

  \special{pdf:mapline gbksongsl@UGBK@ unicode :0:simsun.ttc -s .167 -v 50}
  \special{pdf:mapline gbkkaisl@UGBK@  unicode simkai.ttf -s .167 -v 70}
  \special{pdf:mapline gbkheisl@UGBK@  unicode simhei.ttf -s .167 -v 150}
  \special{pdf:mapline gbkfssl@UGBK@   unicode simfang.ttf -s .167 -v 50}
  \special{pdf:mapline gbklisl@UGBK@   unicode simli.ttf -s .167 -v 150}
  \special{pdf:mapline gbkyousl@UGBK@  unicode simyou.ttf -s .167 -v 60}

  \special{pdf:mapline unisongsl@Unicode@ unicode :0:simsun.ttc -s .167 -v 50}
  \special{pdf:mapline unikaisl@Unicode@  unicode simkai.ttf -s .167 -v 70}
  \special{pdf:mapline uniheisl@Unicode@  unicode simhei.ttf -s .167 -v 150}
  \special{pdf:mapline unifssl@Unicode@   unicode simfang.ttf -s .167 -v 50}
  \special{pdf:mapline unilisl@Unicode@   unicode simli.ttf -s .167 -v 150}
  \special{pdf:mapline uniyousl@Unicode@  unicode simyou.ttf -s .167 -v 60}

%</windows>
%    \end{macrocode}
%
% \paragraph{\pkg{zhadobefonts.tex}}
%
%    \begin{macrocode}
%<*adobe>
\ProvidesFile{zhadobefonts.tex}%
  [2014/06/03 v2.0 Adobe font map loader for DVIPDFMx (CTEX)]

\ifpdf
%% pdfTeX does not support OTF fonts

\else
  \special{pdf:mapline gbk@UGBK@     UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline gbksong@UGBK@ UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline gbkkai@UGBK@  UniGB-UTF16-H AdobeKaitiStd-Regular.otf}
  \special{pdf:mapline gbkhei@UGBK@  UniGB-UTF16-H AdobeHeitiStd-Regular.otf}
  \special{pdf:mapline gbkfs@UGBK@   UniGB-UTF16-H AdobeFangsongStd-Regular.otf}

  \special{pdf:mapline cyberb@Unicode@  UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline unisong@Unicode@ UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline unikai@Unicode@  UniGB-UTF16-H AdobeKaitiStd-Regular.otf}
  \special{pdf:mapline unihei@Unicode@  UniGB-UTF16-H AdobeHeitiStd-Regular.otf}
  \special{pdf:mapline unifs@Unicode@   UniGB-UTF16-H AdobeFangsongStd-Regular.otf}

  \special{pdf:mapline gbksongsl@UGBK@ UniGB-UTF16-H AdobeSongStd-Light.otf -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@  UniGB-UTF16-H AdobeKaitiStd-Regular.otf -s .167}
  \special{pdf:mapline gbkheisl@UGBK@  UniGB-UTF16-H AdobeHeitiStd-Regular.otf -s .167}
  \special{pdf:mapline gbkfssl@UGBK@   UniGB-UTF16-H AdobeFangsongStd-Regular.otf -s .167}

  \special{pdf:mapline unisongsl@Unicode@ UniGB-UTF16-H AdobeSongStd-Light.otf -s .167}
  \special{pdf:mapline unikaisl@Unicode@  UniGB-UTF16-H AdobeKaitiStd-Regular.otf -s .167}
  \special{pdf:mapline uniheisl@Unicode@  UniGB-UTF16-H AdobeHeitiStd-Regular.otf -s .167}
  \special{pdf:mapline unifssl@Unicode@   UniGB-UTF16-H AdobeFangsongStd-Regular.otf -s .167}

%</adobe>
%    \end{macrocode}
%
% \paragraph{\pkg{zhfandolfonts.tex}}
%
%    \begin{macrocode}
%<*fandol>
\ProvidesFile{zhfandolfonts.tex}%
  [2014/06/03 v2.0 Fandol font map loader for DVIPDFMx (CTEX)]

\ifpdf
%% pdfTeX does not support OTF fonts

\else
  \special{pdf:mapline gbk@UGBK@     UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline gbksong@UGBK@ UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline gbkkai@UGBK@  UniGB-UTF16-H FandolKai-Regular.otf}
  \special{pdf:mapline gbkhei@UGBK@  UniGB-UTF16-H FandolHei-Regular.otf}
  \special{pdf:mapline gbkfs@UGBK@   UniGB-UTF16-H FandolFang-Regular.otf}

  \special{pdf:mapline cyberb@Unicode@  UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline unisong@Unicode@ UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline unikai@Unicode@  UniGB-UTF16-H FandolKai-Regular.otf}
  \special{pdf:mapline unihei@Unicode@  UniGB-UTF16-H FandolHei-Regular.otf}
  \special{pdf:mapline unifs@Unicode@   UniGB-UTF16-H FandolFang-Regular.otf}

  \special{pdf:mapline gbksongsl@UGBK@ UniGB-UTF16-H FandolSong-Regular.otf -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@  UniGB-UTF16-H FandolKai-Regular.otf -s .167}
  \special{pdf:mapline gbkheisl@UGBK@  UniGB-UTF16-H FandolHei-Regular.otf -s .167}
  \special{pdf:mapline gbkfssl@UGBK@   UniGB-UTF16-H FandolFang-Regular.otf -s .167}

  \special{pdf:mapline unisongsl@Unicode@ UniGB-UTF16-H FandolSong-Regular.otf -s .167}
  \special{pdf:mapline unikaisl@Unicode@  UniGB-UTF16-H FandolKai-Regular.otf -s .167}
  \special{pdf:mapline uniheisl@Unicode@  UniGB-UTF16-H FandolHei-Regular.otf -s .167}
  \special{pdf:mapline unifssl@Unicode@   UniGB-UTF16-H FandolFang-Regular.otf -s .167}

%</fandol>
%    \end{macrocode}
%
% \paragraph{\pkg{zhfounderfonts.tex}}
%
%    \begin{macrocode}
%<*founder>
\ProvidesFile{zhfounderfonts.tex}%
  [2014/06/03 v2.0 Founder font map loader for pdfTeX and DVIPDFMx (CTEX)]

\ifpdf
  \pdfmapline{=gbk@UGBK@     <FZSSK.TTF}
  \pdfmapline{=gbksong@UGBK@ <FZSSK.TTF}
  \pdfmapline{=gbkkai@UGBK@  <FZKTK.TTF}
  \pdfmapline{=gbkhei@UGBK@  <FZHTK.TTF}
  \pdfmapline{=gbkfs@UGBK@   <FZFSK.TTF}
  \pdfmapline{=gbkli@UGBK@   <FZLSK.TTF}
  \pdfmapline{=gbkyou@UGBK@  <FZY1K.TTF}

  \pdfmapline{=cyberb@Unicode@  <FZSSK.TTF}
  \pdfmapline{=unisong@Unicode@ <FZSSK.TTF}
  \pdfmapline{=unikai@Unicode@  <FZKTK.TTF}
  \pdfmapline{=unihei@Unicode@  <FZHTK.TTF}
  \pdfmapline{=unifs@Unicode@   <FZFSK.TTF}
  \pdfmapline{=unili@Unicode@   <FZLSK.TTF}
  \pdfmapline{=uniyou@Unicode@  <FZY1K.TTF}

  \pdfmapline{=gbksongsl@UGBK@ <FZSSK.TTF}
  \pdfmapline{=gbkkaisl@UGBK@  <FZKTK.TTF}
  \pdfmapline{=gbkheisl@UGBK@  <FZHTK.TTF}
  \pdfmapline{=gbkfssl@UGBK@   <FZFSK.TTF}
  \pdfmapline{=gbklisl@UGBK@   <FZLSK.TTF}
  \pdfmapline{=gbkyousl@UGBK@  <FZY1K.TTF}

  \pdfmapline{=unisongsl@Unicode@ <FZSSK.TTF}
  \pdfmapline{=unikaisl@Unicode@  <FZKTK.TTF}
  \pdfmapline{=uniheisl@Unicode@  <FZHTK.TTF}
  \pdfmapline{=unifssl@Unicode@   <FZFSK.TTF}
  \pdfmapline{=unilisl@Unicode@   <FZLSK.TTF}
  \pdfmapline{=uniyousl@Unicode@  <FZY1K.TTF}

\else
  \special{pdf:mapline gbk@UGBK@     unicode FZSSK.TTF}
  \special{pdf:mapline gbksong@UGBK@ unicode FZSSK.TTF}
  \special{pdf:mapline gbkkai@UGBK@  unicode FZKTK.TTF}
  \special{pdf:mapline gbkhei@UGBK@  unicode FZHTK.TTF}
  \special{pdf:mapline gbkfs@UGBK@   unicode FZFSK.TTF}
  \special{pdf:mapline gbkli@UGBK@   unicode FZLSK.TTF}
  \special{pdf:mapline gbkyou@UGBK@  unicode FZY1K.TTF}

  \special{pdf:mapline cyberb@Unicode@  unicode FZSSK.TTF}
  \special{pdf:mapline unisong@Unicode@ unicode FZSSK.TTF}
  \special{pdf:mapline unikai@Unicode@  unicode FZKTK.TTF}
  \special{pdf:mapline unihei@Unicode@  unicode FZHTK.TTF}
  \special{pdf:mapline unifs@Unicode@   unicode FZFSK.TTF}
  \special{pdf:mapline unili@Unicode@   unicode FZLSK.TTF}
  \special{pdf:mapline uniyou@Unicode@  unicode FZY1K.TTF}

  \special{pdf:mapline gbksongsl@UGBK@ unicode FZSSK.TTF -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@  unicode FZKTK.TTF -s .167}
  \special{pdf:mapline gbkheisl@UGBK@  unicode FZHTK.TTF -s .167}
  \special{pdf:mapline gbkfssl@UGBK@   unicode FZFSK.TTF -s .167}
  \special{pdf:mapline gbklisl@UGBK@   unicode FZLSK.TTF -s .167}
  \special{pdf:mapline gbkyousl@UGBK@  unicode FZY1K.TTF -s .167}

  \special{pdf:mapline unisongsl@Unicode@ unicode FZSSK.TTF -s .167}
  \special{pdf:mapline unikaisl@Unicode@  unicode FZKTK.TTF -s .167}
  \special{pdf:mapline uniheisl@Unicode@  unicode FZHTK.TTF -s .167}
  \special{pdf:mapline unifssl@Unicode@   unicode FZFSK.TTF -s .167}
  \special{pdf:mapline unilisl@Unicode@   unicode FZLSK.TTF -s .167}
  \special{pdf:mapline uniyousl@Unicode@  unicode FZY1K.TTF -s .167}

%</founder>
%    \end{macrocode}
%
% \paragraph{\pkg{zhubuntufonts.tex}}
%
%    \begin{macrocode}
%<*ubuntu>
\ProvidesFile{zhubuntufonts.tex}%
  [2014/06/03 v2.0 Ubuntu font map loader for pdfTeX and DVIPDFMx (CTEX)]

\ifpdf
  \pdfmapline{=gbk@UGBK@     <uming.ttc}
  \pdfmapline{=gbksong@UGBK@ <uming.ttc}
  \pdfmapline{=gbkkai@UGBK@  <ukai.ttc}
  \pdfmapline{=gbkhei@UGBK@  <wqy-zenhei.ttc}
  \pdfmapline{=gbkfs@UGBK@   <uming.ttc}
  \pdfmapline{=gbkyou@UGBK@  <wqy-zenhei.ttc}

  \pdfmapline{=cyberb@Unicode@  <uming.ttc}
  \pdfmapline{=unisong@Unicode@ <uming.ttc}
  \pdfmapline{=unikai@Unicode@  <ukai.ttc}
  \pdfmapline{=unihei@Unicode@  <wqy-zenhei.ttc}
  \pdfmapline{=unifs@Unicode@   <uming.ttc}
  \pdfmapline{=uniyou@Unicode@  <wqy-zenhei.ttc}

  \pdfmapline{=gbksongsl@UGBK@ <uming.ttc}
  \pdfmapline{=gbkkaisl@UGBK@  <ukai.ttc}
  \pdfmapline{=gbkheisl@UGBK@  <wqy-zenhei.ttc}
  \pdfmapline{=gbkfssl@UGBK@   <uming.ttc}
  \pdfmapline{=gbkyousl@UGBK@  <wqy-zenhei.ttc}

  \pdfmapline{=unisongsl@Unicode@ <uming.ttc}
  \pdfmapline{=unikaisl@Unicode@  <ukai.ttc}
  \pdfmapline{=uniheisl@Unicode@  <wqy-zenhei.ttc}
  \pdfmapline{=unifssl@Unicode@   <uming.ttc}
  \pdfmapline{=uniyousl@Unicode@  <wqy-zenhei.ttc}

\else
  \special{pdf:mapline gbk@UGBK@     unicode :0:uming.ttc}
  \special{pdf:mapline gbksong@UGBK@ unicode :0:uming.ttc}
  \special{pdf:mapline gbkkai@UGBK@  unicode :0:ukai.ttc}
  \special{pdf:mapline gbkhei@UGBK@  unicode :0:wqy-zenhei.ttc}
  \special{pdf:mapline gbkfs@UGBK@   unicode :0:uming.ttc}

  \special{pdf:mapline cyberb@Unicode@  unicode :0:uming.ttc}
  \special{pdf:mapline unisong@Unicode@ unicode :0:uming.ttc}
  \special{pdf:mapline unikai@Unicode@  unicode :0:ukai.ttc}
  \special{pdf:mapline unihei@Unicode@  unicode :0:wqy-zenhei.ttc}
  \special{pdf:mapline unifs@Unicode@   unicode :0:uming.ttc}

  \special{pdf:mapline gbksongsl@UGBK@ unicode :0:uming.ttc -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@  unicode :0:ukai.ttc -s .167}
  \special{pdf:mapline gbkheisl@UGBK@  unicode :0:wqy-zenhei.ttc -s .167}
  \special{pdf:mapline gbkfssl@UGBK@   unicode :0:uming.ttc -s .167}

  \special{pdf:mapline unisongsl@Unicode@ unicode :0:uming.ttc -s .167}
  \special{pdf:mapline unikaisl@Unicode@  unicode :0:ukai.ttc -s .167}
  \special{pdf:mapline uniheisl@Unicode@  unicode :0:wqy-zenhei.ttc -s .167}
  \special{pdf:mapline unifssl@Unicode@   unicode :0:uming.ttc -s .167}

%</ubuntu>
%    \end{macrocode}
%
%    \begin{macrocode}
\fi

\ctex@zhmap@endinput
%</zhmap>
%    \end{macrocode}
%
% \subsubsection{制作 \texttt{spa} 文件}
%
% 我们通过 \XeTeX{} 的 \tn{XeTeXglyphbounds} 取得字体中标点符号的边界信息，为
% \pkg{CJKpunct} 宏包制作 \file{spa}。
%
%    \begin{macrocode}
%<*spa>
%<*macro>
\input expl3-generic %
\ExplSyntaxOn
\xetex_if_engine:F
  {
    \msg_new:nn { ctex } { xetex }
      { XeTeX~is~required~to~compile~this~document! }
    \msg_fatal:nn { ctex } { xetex }
  }
%    \end{macrocode}
%
% \pkg{CJKpunct} 定义的标点符号是：
% \begin{verbatim}
%   ‘“「『〔（［｛〈《〖【
%   —…、。，．：；！？％〕）］｝〉》〗】’”」』
% \end{verbatim}
% 注意顺序不能改变。
%    \begin{macrocode}
\seq_new:N \c_@@_punct_seq
\seq_gset_from_clist:Nn \c_@@_punct_seq
  {
    "2018 , "201C , "300C , "300E , "3014 , "FF08 , "FF3B , "FF5B ,
    "3008 , "300A , "3016 , "3010 ,
    "2014 , "2026 , "3001 , "3002 , "FF0C , "FF0E , "FF1A , "FF1B ,
    "FF01 , "FF1F , "FF05 , "3015 , "FF09 , "FF3D , "FF5D , "3009 ,
    "300B , "3017 , "3011 , "2019 , "201D , "300D , "300F
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ctex_make_spa:nn}
% |#1| 是 \file{spa} 文件名，|#2| 是由 CJK 族名与字体构成的逗号列表。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_make_spa:nn #1#2
  {
    \iow_open:Nn \g_@@_spa_iow {#1}
    \clist_map_inline:nn {#2}
      { \@@_write_family:nn ##1 }
    \iow_close:N \g_@@_spa_iow
  }
\iow_new:N \g_@@_spa_iow
\cs_new_eq:NN \MAKESPA \ctex_make_spa:nn
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_write_family:nn #1#2
  {
    \group_begin:
      \tex_font:D \l_@@_punct_font = "#2" ~ at ~ 100 pt \scan_stop:
      \l_@@_punct_font
      \clist_clear:N \l_@@_punct_bounds_clist
      \seq_map_inline:Nn \c_@@_punct_seq
        { \exp_args:No \@@_save_bounds:n { \int_use:N \XeTeXcharglyph ##1 } }
      \iow_now:Nx \g_@@_spa_iow
        {
          \token_to_str:N \@namedef { CJKpunct@#1@spaces }
%    \end{macrocode}
% 最后这三个逗号对 \pkg{CJKpunct} 来说是必要的。
%    \begin{macrocode}
            { \l_@@_punct_bounds_clist , , , }
        }
    \group_end:
  }
\cs_new_protected_nopar:Npn \@@_save_bounds:n #1
  {
    \clist_put_right:Nx \l_@@_punct_bounds_clist
      {
        \@@_calc_bounds:nn { \c_one }   {#1} ,
        \@@_calc_bounds:nn { \c_three } {#1}
      }
  }
\clist_new:N \l_@@_punct_bounds_clist
%    \end{macrocode}
%
% \pkg{CJKpunct} 要求的格式是边界空白宽度与 1\,em 的比值的一百倍。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_calc_bounds:nn #1#2
  {
    \fp_eval:n
      { round ( \dim_to_unit:nn { 100 \XeTeXglyphbounds #1 ~ #2 } { 1 em } ) }
  }
\ExplSyntaxOff
%</macro>
%    \end{macrocode}
%
% 下面是 \CTeX{} 定义的一些字体。
%    \begin{macrocode}
%<*make>
\input ctexspamacro %

\MAKESPA {ctexpunct.spa}
  {
    {adobezhsong}     {AdobeSongStd-Light} ,
    {adobezhhei}      {AdobeHeitiStd-Regular} ,
    {adobezhkai}      {AdobeKaitiStd-Regular} ,
    {adobezhfs}       {AdobeFangsongStd-Regular} ,
    {fandolzhsong}    {FandolSong} ,
    {fandolzhsongb}   {FandolSong-Bold} ,
    {fandolzhhei}     {FandolHei} ,
    {fandolzhheib}    {FandolHei-Bold} ,
    {fandolzhkai}     {FandolKai} ,
    {fandolzhfs}      {FandolFang} ,
    {founderzhsong}   {FZShuSong-Z01} ,
    {founderzhsongb}  {FZXiaoBiaoSong-B05} ,
    {founderzhhei}    {FZHei-B01} ,
    {founderzhheil}   {FZXiHeiI-Z08} ,
    {founderzhkai}    {FZKai-Z03} ,
    {founderzhfs}     {FZFangSong-Z02} ,
    {founderzhli}     {FZLiShu-S01} ,
    {founderzhyou}    {FZXiYuan-M01} ,
    {founderzhyoub}   {FZZhunYuan-M02} ,
    {ubuntuzhsong}    {AR PL UMing CN} ,
    {ubuntuzhhei}     {WenQuanYi Zen Hei} ,
    {ubuntuzhkai}     {AR PL UKai CN} ,
    {windowszhsong}   {SimSun} ,
    {windowszhhei}    {SimHei} ,
    {windowszhkai}    {KaiTi} ,
    {windowszhfs}     {FangSong} ,
    {windowszhli}     {LiSu} ,
    {windowszhyou}    {YouYuan} ,
    {windowszhyahei}  {Microsoft YaHei} ,
    {windowszhyaheib} {Microsoft YaHei Bold}
  }

\primitive\end
%</make>
%</spa>
%    \end{macrocode}
%
% \end{implementation}
%
% \Finale
%
\endinput
